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

RSWW-138 websocket in data generator module #57

Merged
merged 20 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0671591
RSWW-138 set up websocket connection on the data generator side
Danzigerrr Jun 5, 2024
5f5d869
RSWW-138 fix errors with websocket connection
Danzigerrr Jun 5, 2024
d9ec4cb
RSWW-138 update calculating random hotels data
Danzigerrr Jun 5, 2024
6e0de89
RSWW-138 delete controller - made for tests
Danzigerrr Jun 5, 2024
9801a85
RSWW-138 refactoring - change classes' names
Danzigerrr Jun 5, 2024
f2c7fbf
RSWW-138 set up websocket for transports updates
Danzigerrr Jun 5, 2024
b24f060
RSWW-138 adjust schedule delays
Danzigerrr Jun 5, 2024
dcb75eb
RSWW-138 refactor - change location of websocket handlers
Danzigerrr Jun 5, 2024
6b1931a
RSWW-138 set up rabbitmq communication for room reservation updates
Danzigerrr Jun 5, 2024
fbe9b25
RSWW-138 set up rabbitmq communication for transport reservation updates
Danzigerrr Jun 5, 2024
c64fb99
RSWW-138 update rabbitmq hotels communication
Danzigerrr Jun 5, 2024
ae4dbea
RSWW-138 fix issues with creating and deleting resrevations
Danzigerrr Jun 5, 2024
4d0ff13
RSWW-138 select only rooms without reservations
Danzigerrr Jun 5, 2024
4052ef5
RSWW-138 select only transport without reservations
Danzigerrr Jun 5, 2024
7ab06a4
RSWW-138 adjust calculating new price per adult during data update
Danzigerrr Jun 7, 2024
9a7c27e
RSWW-138 use logger instead of println
Danzigerrr Jun 7, 2024
2a2d669
RSWW-138 select a random room (with or without reservations)
Danzigerrr Jun 7, 2024
9997844
RSWW-138 select a random transport with or without reservations
Danzigerrr Jun 7, 2024
8a647b5
RSWW-138 create reservations for transports in Bootstrap
Danzigerrr Jun 7, 2024
64ad88f
RSWW-138 save created/updated objects in the repositories
Danzigerrr Jun 8, 2024
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: 9 additions & 0 deletions api-gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,14 @@ spring:
- Path=/payments/**
filters:
- RemoveRequestHeader=Cookie
- id: data-generator
uri: lb://data-generator
predicates:
- Path=/data-generator/**
metadata:
cors:
allowedOrigins: '*'
allowedMethods: '*'
allowedHeaders: '*'
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
64 changes: 46 additions & 18 deletions data-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,41 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<version>3.2.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cloud.project</groupId>
<groupId>org.microarchitecturovisco</groupId>
<artifactId>data-generator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>data-generator</name>
<description>data-generator</description>
<properties>
<java.version>21</java.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand All @@ -33,13 +51,9 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -51,21 +65,35 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
<scope>compile</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

import cloud.project.datagenerator.hotels.domain.Hotel;
import cloud.project.datagenerator.hotels.domain.Room;
import cloud.project.datagenerator.hotels.repositories.HotelRepository;
import cloud.project.datagenerator.rabbitmq.QueuesConfig;
import cloud.project.datagenerator.hotels.repositories.RoomRepository;
import cloud.project.datagenerator.hotels.utils.HotelUtils;
import cloud.project.datagenerator.rabbitmq.QueuesConfigHotels;
import cloud.project.datagenerator.rabbitmq.json.JsonConverter;
import cloud.project.datagenerator.rabbitmq.requests.RoomUpdateRequest;
import cloud.project.datagenerator.rabbitmq.requests.hotels.RoomUpdateRequest;
import cloud.project.datagenerator.websockets.hotels.DataGeneratorHotelsWebSocketHandler;
import cloud.project.datagenerator.websockets.hotels.HotelUpdate;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.time.LocalDateTime;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Logger;

@Component
@RequiredArgsConstructor
Expand All @@ -23,11 +27,14 @@ enum DataUpdateType {
UPDATE
}

private final HotelRepository hotelRepository;
private final Random random = new Random();
private final RabbitTemplate rabbitTemplate;
private final DataGeneratorHotelsWebSocketHandler dataGeneratorHotelsWebSocketHandler;
private final Logger logger = Logger.getLogger("DataGenerator | Hotels");
private final HotelUtils hotelUtils;
private final RoomRepository roomRepository;

@Scheduled(fixedDelay = 5000, initialDelay = 5000)
@Scheduled(fixedDelay = 5000, initialDelay = 10000)
public void updateRandomHotelData() {
int action = random.nextInt(2);

Expand All @@ -42,7 +49,7 @@ public void updateRandomHotelData() {
}

private void createNewRoom() {
Hotel randomHotel = getRandomHotel();
Hotel randomHotel = hotelUtils.getRandomHotel();
if (randomHotel == null) return;

Room newRoom = Room.builder()
Expand All @@ -54,47 +61,37 @@ private void createNewRoom() {
.description("This is an awesome new room generated by Data Generator module")
.build();

roomRepository.save(newRoom);

updateHotelDataInHotelModules(DataUpdateType.CREATE, newRoom);

updateHotelUpdatesOnFrontend(DataUpdateType.CREATE, newRoom.getName(), randomHotel.getName(), 0, 0);
}

private void updateRandomRoom() {
Hotel randomHotel = getRandomHotel();
Hotel randomHotel = hotelUtils.getRandomHotel();
if (randomHotel == null) return;

Room randomRoom = randomHotel.getRooms().get(random.nextInt(randomHotel.getRooms().size()));
Room randomRoom = hotelUtils.getRandomRoomFromHotel(randomHotel);
if (randomRoom == null) return;

int currentGuestCapacity = randomRoom.getGuestCapacity();
int newGuestCapacity = random.nextInt(1, currentGuestCapacity + 10);
int newGuestCapacity = random.nextInt(currentGuestCapacity, currentGuestCapacity + 10);

float currentPricePerAdult = randomRoom.getPricePerAdult();
float newPricePerAdult = random.nextFloat(currentPricePerAdult, currentPricePerAdult*10);
float newPricePerAdult = random.nextFloat(100, currentPricePerAdult + 100);

randomRoom.setGuestCapacity(newGuestCapacity);
randomRoom.setPricePerAdult(newPricePerAdult);

updateHotelDataInHotelModules(DataUpdateType.UPDATE, randomRoom);
}

private Hotel getRandomHotel() {
List<Hotel> hotels = hotelRepository.findAll();

if (hotels.isEmpty()) {
System.out.println("No hotels found.");
return null;
}
roomRepository.save(randomRoom);

Hotel randomHotel;
int attempts = 0;
do {
randomHotel = hotels.get(random.nextInt(hotels.size()));
attempts++;
} while (randomHotel.getRooms().isEmpty() && attempts < hotels.size());
updateHotelDataInHotelModules(DataUpdateType.UPDATE, randomRoom);

if (randomHotel.getRooms().isEmpty()) {
System.out.println("No rooms found in the selected hotel.");
return null;
}
int capacityChange = newGuestCapacity - currentGuestCapacity;
float priceChange = newPricePerAdult - currentPricePerAdult;

return randomHotel;
updateHotelUpdatesOnFrontend(DataUpdateType.UPDATE, randomRoom.getName(), randomHotel.getName(), capacityChange, priceChange);
}

public void updateHotelDataInHotelModules(DataUpdateType updateType, Room room) {
Expand All @@ -110,14 +107,23 @@ public void updateHotelDataInHotelModules(DataUpdateType updateType, Room room)

String roomUpdateRequestJson = JsonConverter.convert(roomUpdateRequest);

System.out.println(updateType + " - Room: " + roomUpdateRequestJson);
logger.info(updateType + " - Room: " + roomUpdateRequestJson);

rabbitTemplate.convertAndSend(QueuesConfig.EXCHANGE_HOTEL_FANOUT_UPDATE_DATA, "", roomUpdateRequestJson);

sendUpdateToFrontend(updateType, room);
rabbitTemplate.convertAndSend(QueuesConfigHotels.EXCHANGE_HOTEL_FANOUT_UPDATE_DATA, "", roomUpdateRequestJson);
}

private void sendUpdateToFrontend(DataUpdateType updateType, Room room){
//TODO: here send a message to frontend via websocket
private void updateHotelUpdatesOnFrontend(DataUpdateType updateType, String roomName, String hotelName, int capacityChange, float priceChange) {
LocalDateTime currentDateAndTime = LocalDateTime.now().withSecond(0).withNano(0);

HotelUpdate hotelUpdate = HotelUpdate.builder()
.updateDateTime(currentDateAndTime)
.updateType(String.valueOf(updateType))
.hotelName(hotelName)
.roomName(roomName)
.priceChange(priceChange)
.capacityChange(capacityChange)
.build();

dataGeneratorHotelsWebSocketHandler.updateHotelList(hotelUpdate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cloud.project.datagenerator.hotels.controllers;

import cloud.project.datagenerator.hotels.domain.Hotel;
import cloud.project.datagenerator.hotels.domain.Room;
import cloud.project.datagenerator.hotels.domain.RoomReservation;
import cloud.project.datagenerator.hotels.repositories.HotelRepository;
import cloud.project.datagenerator.hotels.repositories.RoomReservationRepository;
import cloud.project.datagenerator.rabbitmq.json.JsonReader;
import cloud.project.datagenerator.rabbitmq.requests.hotels.CreateHotelReservationRequest;
import cloud.project.datagenerator.rabbitmq.requests.hotels.DeleteHotelReservationRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.logging.Logger;

@RestController()
@RequiredArgsConstructor
public class HotelsController {

private final HotelRepository hotelRepository;
private final RoomReservationRepository roomReservationRepository;
Logger logger = Logger.getLogger("DataGenerator | Hotels");

@RabbitListener(queues = "#{handleCreateHotelReservationQueue.name}")
public void consumeMessageCreateHotelReservation(String requestJson) {
CreateHotelReservationRequest request = JsonReader.readCreateHotelReservationRequestCommand(requestJson);
logger.info("Creating hotel reservations: " + request);

Hotel hotel = hotelRepository.findById(request.getHotelId()).orElse(null);
assert hotel != null;

int countBefore = hotel.getRooms().stream()
.mapToInt(room -> room.getRoomReservations().size()).sum();

for (UUID roomId : request.getRoomIds()) {
Room room = hotel.getRooms().stream()
.filter(r -> r.getId().equals(roomId))
.findFirst()
.orElse(null);
if (room != null) {
RoomReservation roomReservation = new RoomReservation();
roomReservation.setId(request.getReservationId());
roomReservation.setDateFrom(request.getHotelTimeFrom());
roomReservation.setDateTo(request.getHotelTimeTo());
roomReservation.setRoom(room);
roomReservation.setMainReservationId(request.getReservationId());

room.getRoomReservations().add(roomReservation);
roomReservationRepository.save(roomReservation);
}
}

int countAfter = hotel.getRooms().stream()
.mapToInt(room -> room.getRoomReservations().size()).sum();

logger.info("consumeMessageCreateHotelReservation: " + countBefore + " --> " + countAfter);
}

@RabbitListener(queues = "#{handleDeleteHotelReservationQueue.name}")
public void consumeMessageDeleteHotelReservation(String requestJson) {

DeleteHotelReservationRequest request = JsonReader.readDeleteHotelReservationRequestCommand(requestJson);
logger.info("Deleting hotel reservations: " + request);

Hotel hotel = hotelRepository.findById(request.getHotelId()).orElse(null);
assert hotel != null;

int countBefore = hotel.getRooms().stream()
.mapToInt(room -> room.getRoomReservations().size()).sum();

for (UUID roomId : request.getRoomIds()) {
Room room = hotel.getRooms().stream()
.filter(r -> r.getId().equals(roomId))
.findFirst()
.orElse(null);
if (room != null) {
room.getRoomReservations().removeIf(roomReservation -> roomReservation.getId().equals(request.getReservationId()));
}
}

int countAfter = hotel.getRooms().stream()
.mapToInt(room -> room.getRoomReservations().size()).sum();

logger.info("consumeMessageDeleteHotelReservation: " + countBefore + " --> " + countAfter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.validation.constraints.NotNull;
import lombok.*;

import java.util.List;
import java.util.UUID;


Expand Down Expand Up @@ -33,5 +34,6 @@ public class Room {
@Lob
private String description;

// List of room reservations for each room is empty
@OneToMany(mappedBy="room", fetch = FetchType.EAGER)
private List<RoomReservation> roomReservations;
}
Loading
Loading