Skip to content

Commit

Permalink
Lecture 9, 10 and 11 : Command Handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
madhav0922 committed May 25, 2024
1 parent 0ed3f3a commit edb6b26
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 22 deletions.
12 changes: 12 additions & 0 deletions Initial_Projects/NoBS/src/main/java/com/example/demo/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.demo;

import org.springframework.http.ResponseEntity;


public interface Command <E, T> {
// <E, T> = Entity, T is generic type in java

ResponseEntity <T> execute(E entity);
// we can also name the method handle.. since its a handler.. but execute is also used..

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.demo.Product.Model;

import lombok.Data;

@Data
public class UpdateProductCommand {
private int id;
private Product product;

public UpdateProductCommand(int id, Product product) {
this.id = id;
this.product = product;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.example.demo.Product;

import com.example.demo.Product.Model.Product;
import com.example.demo.Product.Model.UpdateProductCommand;
import com.example.demo.Product.commandHandlers.CreateProductCommandHandler;
import com.example.demo.Product.commandHandlers.DeleteProductCommandHandler;
import com.example.demo.Product.commandHandlers.UpdateProductCommandHandler;
import com.example.demo.Product.queryHandlers.GetAllProductsQueryHandler;
import com.example.demo.Product.queryHandlers.GetProductQueryHandler;
import org.apache.coyote.Response;
Expand Down Expand Up @@ -75,39 +79,67 @@ public ResponseEntity<Product> getProduct(@PathVariable Integer id) {
return getProductQueryHandler.execute(id);
}

// Lecture - 5: POST, PUT and DELETE MAPPING
// // Lecture - 5: POST, PUT and DELETE MAPPING
// @PostMapping
// // @RequestBody will tell that in the HTTP request body look for a product.
// public ResponseEntity createProduct(@RequestBody Product product) {
// // Accept a product through JSON
// // Convert it to a Product
// // Save it in the database
// productRepository.save(product); // Currently we do not have any data validation.
// return ResponseEntity.ok().build(); // This wont return anything in the body for now. Only returns a 200
// // response code.
// }

// Lecture 9 : Command Handler
@Autowired
private CreateProductCommandHandler createProductCommandHandler;
@PostMapping
// @RequestBody will tell that in the HTTP request body look for a product.
public ResponseEntity createProduct(@RequestBody Product product) {
// Accept a product through JSON
// Convert it to a Product
// Save it in the database
productRepository.save(product); // Currently we do not have any data validation.
return ResponseEntity.ok().build(); // This wont return anything in the body for now. Only returns a 200
// response code.
public ResponseEntity<String> createProduct(@RequestBody Product product) {
return createProductCommandHandler.execute(product);
}

// PUT is kind of a combination of GET AND POST.
// @PutMapping("/{id}")
// public ResponseEntity updateProduct(@PathVariable Integer id, @RequestBody Product product) {
// // We would require the id to update the product
// // Again we are not doing any validation here.
// // We are doing this id thing manually just to see. We could have passed the ID
// // in the product itself.
// product.setId(id); // Helps set the id so that retrieval / update becomes easy.
// productRepository.save(product); // updates the given product for the id set above.
// return ResponseEntity.ok().build();
// }

// Lecture 10 : Command Handler 2
@Autowired
UpdateProductCommandHandler updateProductCommandHandler;
@PutMapping("/{id}")
public ResponseEntity updateProduct(@PathVariable Integer id, @RequestBody Product product) {
// We would require the id to update the product
// Again we are not doing any validation here.
// We are doing this id thing manually just to see. We could have passed the ID
// in the product itself.
product.setId(id); // Helps set the id so that retrieval / update becomes easy.
productRepository.save(product); // updates the given product for the id set above.
return ResponseEntity.ok().build();
UpdateProductCommand updateProductCommand = new UpdateProductCommand(id, product);
return updateProductCommandHandler.execute(updateProductCommand);
}

// @DeleteMapping("/{id}")
// public ResponseEntity deleteProduct(@PathVariable Integer id) {
// Product product = productRepository.findById(id).get();
// productRepository.delete(product);
//
// // OR..
// // productRepository.deleteById(id);
//
// return ResponseEntity.ok().build();
// }

// Lecture 11 : Command Handler 3
@Autowired
private DeleteProductCommandHandler deleteProductCommandHandler;
@DeleteMapping("/{id}")
public ResponseEntity deleteProduct(@PathVariable Integer id) {
Product product = productRepository.findById(id).get();
productRepository.delete(product);

// OR..
// productRepository.deleteById(id);

return ResponseEntity.ok().build();
// Not fully done yet as we have not handled the Optional (nullable) yet... in case we don't find the product with the given id.
// It'd be done in further classes with custom exception...
return deleteProductCommandHandler.execute(id);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.example.demo.Product.commandHandlers;

import com.example.demo.Command;
import com.example.demo.Product.Model.Product;
import com.example.demo.Product.ProductRepository;
import io.micrometer.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

// Lecture 9 : Command Handler
@Service
public class CreateProductCommandHandler implements Command<Product, String> {

@Autowired // allows us to inject the product repository and access it in the command handler.
private ProductRepository productRepository;
@Override
public ResponseEntity<String> execute(Product product) {
// Validate then save...
checkValidation(product);

// Validation provides the safety for our app here...
// The validation won't allow to save a wrong product and will throw an exception and stop execution.

productRepository.save(product);
return ResponseEntity.ok().build();
}

private void checkValidation(Product product) {
// name
if (StringUtils.isBlank(product.getName())) { // micrometer utils... check import
throw new RuntimeException("Product name cannot be empty");
}
// description
if(StringUtils.isBlank(product.getDescription())) {
throw new RuntimeException("Description cannot be empty");
}
// price
if(product.getPrice() <= 0.0) {
throw new RuntimeException("Price cannot be negative or 0");
}
// quantity
if(product.getQuantity() <= 0) {
throw new RuntimeException("Quantity cannot be negative or 0");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.demo.Product.commandHandlers;

import com.example.demo.Command;
import com.example.demo.Product.Model.Product;
import com.example.demo.Product.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Service
public class DeleteProductCommandHandler implements Command<Integer, ResponseEntity> {

@Autowired
private ProductRepository productRepository;
@Override
public ResponseEntity<ResponseEntity> execute(Integer id) {
Product product = productRepository.getReferenceById(id);
productRepository.delete(product);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.demo.Product.commandHandlers;

import com.example.demo.Command;
import com.example.demo.Product.Model.Product;
import com.example.demo.Product.Model.UpdateProductCommand;
import com.example.demo.Product.ProductRepository;
import io.micrometer.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Service
public class UpdateProductCommandHandler implements Command<UpdateProductCommand, ResponseEntity> {

@Autowired
private ProductRepository productRepository;
@Override
public ResponseEntity execute(UpdateProductCommand command) {
Product product = command.getProduct();
// validate product
checkValidation(product);
product.setId(command.getId());
// If this is not done and the entry does not already exist in the database
// then it will work just like POST command else it will create a new entry.
productRepository.save(product);
return ResponseEntity.ok().build();
}

// This method could be abstracted even more as it is being used in multiple classes...
// by making something like another utility class
private void checkValidation(Product product) {
// name
if (StringUtils.isBlank(product.getName())) { // micrometer utils... check import
throw new RuntimeException("Product name cannot be empty");
}
// description
if(StringUtils.isBlank(product.getDescription())) {
throw new RuntimeException("Description cannot be empty");
}
// price
if(product.getPrice() <= 0.0) {
throw new RuntimeException("Price cannot be negative or 0");
}
// quantity
if(product.getQuantity() <= 0) {
throw new RuntimeException("Quantity cannot be negative or 0");
}
}
}
2 changes: 2 additions & 0 deletions Initial_Projects/db/NoBS.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

use nobs;

/*
CREATE TABLE product (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
description VARCHAR(255),
price double,
quantity int
);
*/

select * from product;

0 comments on commit edb6b26

Please sign in to comment.