diff --git a/README.md b/README.md index 364c78a..33125ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # JAVA Cloud AWS - Day Five +### Core screenshot +![alt text](aws-day-5-message.png) +![alt text](aws-day-5-SQS.png) +### Extension screenshot +![alt text](aws-day-5-extension.png) ## Commands to Set Up SQS, SNS, and EventBridge Note in Every command and URL being called there are fields that need to be replaced. diff --git a/aws-day-5-SQS.png b/aws-day-5-SQS.png new file mode 100644 index 0000000..7c20ad9 Binary files /dev/null and b/aws-day-5-SQS.png differ diff --git a/aws-day-5-extension.png b/aws-day-5-extension.png new file mode 100644 index 0000000..bfd5752 Binary files /dev/null and b/aws-day-5-extension.png differ diff --git a/aws-day-5-message.png b/aws-day-5-message.png new file mode 100644 index 0000000..a72a674 Binary files /dev/null and b/aws-day-5-message.png differ diff --git a/src/main/java/com/booleanuk/Main.java b/src/main/java/com/booleanuk/Main.java index 047793c..d6833d5 100644 --- a/src/main/java/com/booleanuk/Main.java +++ b/src/main/java/com/booleanuk/Main.java @@ -4,9 +4,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Import; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @Import({OrderController.class}) +@EnableScheduling public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); diff --git a/src/main/java/com/booleanuk/OrderService/controllers/OrderController.java b/src/main/java/com/booleanuk/OrderService/controllers/OrderController.java index 39cdc87..6cb6c31 100644 --- a/src/main/java/com/booleanuk/OrderService/controllers/OrderController.java +++ b/src/main/java/com/booleanuk/OrderService/controllers/OrderController.java @@ -2,14 +2,17 @@ import com.booleanuk.OrderService.models.Order; +import com.booleanuk.OrderService.repositories.OrderRepository; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.*; -import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.eventbridge.EventBridgeClient; import software.amazon.awssdk.services.eventbridge.model.PutEventsRequest; import software.amazon.awssdk.services.eventbridge.model.PutEventsRequestEntry; @@ -21,6 +24,7 @@ import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; import java.util.List; +import java.util.Optional; @RestController @RequestMapping("orders") @@ -33,32 +37,49 @@ public class OrderController { private String topicArn; private String eventBusName; + @Autowired + private OrderRepository repository; + public OrderController() { this.sqsClient = SqsClient.builder().build(); this.snsClient = SnsClient.builder().build(); this.eventBridgeClient = EventBridgeClient.builder().build(); - this.queueUrl = ""; - this.topicArn = ""; - this.eventBusName = ""; + this.queueUrl = "https://sqs.eu-west-1.amazonaws.com/637423341661/SimpFredOrderQueue"; + this.topicArn = "arn:aws:sns:eu-west-1:637423341661:SimpFredOrderCreatedTopic"; + this.eventBusName = "arn:aws:events:eu-west-1:637423341661:event-bus/SimpFredCustomEventBus"; this.objectMapper = new ObjectMapper(); } @GetMapping - public ResponseEntity GetAllOrders() { + public ResponseEntity> getAllOrders() { + List orders = repository.findAll(); + return ResponseEntity.ok(orders); + } + + @Scheduled(fixedRate = 5000) + public void processOrdersFromQueue() { ReceiveMessageRequest receiveRequest = ReceiveMessageRequest.builder() .queueUrl(queueUrl) .maxNumberOfMessages(10) - .waitTimeSeconds(20) + .waitTimeSeconds(1) .build(); List messages = sqsClient.receiveMessage(receiveRequest).messages(); + System.out.println("Received messages from the queue: " + messages.size()); for (Message message : messages) { try { - Order order = this.objectMapper.readValue(message.body(), Order.class); - this.processOrder(order); + // Extract the "Message" field from the SNS notification + JsonNode messageNode = objectMapper.readTree(message.body()); + String orderJson = messageNode.get("Message").asText(); + + System.out.println(orderJson); + + // Deserialize the order JSON to an Order object + Order order = objectMapper.readValue(orderJson, Order.class); + finalizeOrder(order); DeleteMessageRequest deleteRequest = DeleteMessageRequest.builder() .queueUrl(queueUrl) @@ -67,15 +88,38 @@ public ResponseEntity GetAllOrders() { sqsClient.deleteMessage(deleteRequest); } catch (JsonProcessingException e) { -// e.printStackTrace(); + e.printStackTrace(); } } - String status = String.format("%d Orders have been processed", messages.size()); - return ResponseEntity.ok(status); + System.out.println("Processed orders in background: " + messages.size()); } @PostMapping - public ResponseEntity createOrder(@RequestBody Order order) { + public ResponseEntity createOrder(@RequestBody Order order) { + System.out.println(order.toString()); + Order newOrder = repository.save(order); + publishOrderEvent(newOrder); + return new ResponseEntity<>(newOrder, HttpStatus.CREATED); + } + + @PutMapping("/{id}") + public ResponseEntity updateOrder(@PathVariable int id, @RequestBody Order orderDetails) { + Optional optionalOrder = repository.findById(id); + if (optionalOrder.isPresent()) { + Order order = optionalOrder.get(); + order.setProduct(orderDetails.getProduct()); + order.setQuantity(orderDetails.getQuantity()); + order.setAmount(orderDetails.getAmount()); + order.setProcessed(orderDetails.isProcessed()); + Order updatedOrder = repository.save(order); + publishOrderEvent(updatedOrder); + return ResponseEntity.ok(updatedOrder); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + } + + public void publishOrderEvent(Order order) { try { String orderJson = objectMapper.writeValueAsString(order); System.out.println(orderJson); @@ -98,15 +142,15 @@ public ResponseEntity createOrder(@RequestBody Order order) { this.eventBridgeClient.putEvents(putEventsRequest); - String status = "Order created, Message Published to SNS and Event Emitted to EventBridge"; - return ResponseEntity.ok(status); } catch (JsonProcessingException e) { -// e.printStackTrace(); - return ResponseEntity.status(500).body("Failed to create order"); + e.printStackTrace(); } } - private void processOrder(Order order) { + private void finalizeOrder(Order order) { + order.calculateTotal(); + order.setProcessed(true); + repository.save(order); System.out.println(order.toString()); } -} +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/OrderService/models/Order.java b/src/main/java/com/booleanuk/OrderService/models/Order.java index a7669de..1e99344 100644 --- a/src/main/java/com/booleanuk/OrderService/models/Order.java +++ b/src/main/java/com/booleanuk/OrderService/models/Order.java @@ -1,5 +1,6 @@ package com.booleanuk.OrderService.models; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; @@ -11,6 +12,7 @@ @NoArgsConstructor @AllArgsConstructor @Entity +@JsonIgnoreProperties(ignoreUnknown = true) @Table(name = "orders") public class Order { @Id @@ -39,4 +41,19 @@ public Order(String product, int quantity, int amount, boolean processed, int to this.processed = processed; this.total = total; } + + public void calculateTotal() { + this.total = this.quantity * this.amount; + } + + public String toString() { + return "Order{" + + "id=" + id + + ", product='" + product + '\'' + + ", quantity=" + quantity + + ", amount=" + amount + + ", processed=" + processed + + ", total=" + total + + '}'; + } }