diff --git a/car/pom.xml b/car/pom.xml index 0cdce75d25cebfa6d17d72debc8479989c33db75..8472300c295cb65a215a847dd2aa75eb8297d815 100644 --- a/car/pom.xml +++ b/car/pom.xml @@ -47,18 +47,6 @@ <artifactId>spring-data-jpa</artifactId> <version>3.0.3</version> </dependency> - <dependency> - <groupId>fi.muni</groupId> - <artifactId>driver</artifactId> - <version>0.0.1-SNAPSHOT</version> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>fi.muni</groupId> - <artifactId>component</artifactId> - <version>0.0.1-SNAPSHOT</version> - <scope>compile</scope> - </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> diff --git a/car/src/main/java/cz/muni/pa165/car/App.java b/car/src/main/java/cz/muni/pa165/car/App.java index 028b53c9ccabcbecfd159a8e7d86da67a070f0c7..af2d25f5e666eb2af9d28fea87c26bf030d755eb 100644 --- a/car/src/main/java/cz/muni/pa165/car/App.java +++ b/car/src/main/java/cz/muni/pa165/car/App.java @@ -1,10 +1,7 @@ package cz.muni.pa165.car; import cz.muni.pa165.car.data.model.Car; -import cz.muni.pa165.common_library.client.ClientConfig; import cz.muni.pa165.common_library.exception.RestExceptionHandler; -import cz.muni.pa165.component.data.model.CarComponent; -import cz.muni.pa165.driver.data.model.Driver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -20,7 +17,7 @@ import org.springframework.web.client.RestTemplate; @SpringBootApplication //@EnableJpaRepositories(basePackages = {"cz.muni.pa165.car.data.repository"}) @EnableTransactionManagement -@EntityScan(basePackageClasses = {Car.class, Driver.class, CarComponent.class}) +@EntityScan(basePackageClasses = {Car.class}) //@Import({RestExceptionHandler.class, ClientConfig.class}) @Import(RestExceptionHandler.class) public class App { diff --git a/car/src/main/java/cz/muni/pa165/car/data/model/Car.java b/car/src/main/java/cz/muni/pa165/car/data/model/Car.java index 75d61eed69f2b7274cb105df5fe2a7f16c852360..1d4d9ed2fff499e5b526ff122c9de2632b839ef1 100644 --- a/car/src/main/java/cz/muni/pa165/car/data/model/Car.java +++ b/car/src/main/java/cz/muni/pa165/car/data/model/Car.java @@ -8,7 +8,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.io.Serializable; -import java.util.List; +import java.util.Set; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,10 +30,10 @@ public class Car implements Serializable { private Long id; @ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER) - private List<Long> components; + private Set<Long> components; @ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER) - private List<Long> drivers; + private Set<Long> drivers; private Long mainDriverId; diff --git a/car/src/main/java/cz/muni/pa165/car/data/repository/CarComponentPairRepository.java b/car/src/main/java/cz/muni/pa165/car/data/repository/CarComponentPairRepository.java deleted file mode 100644 index 2a9f5a730a2a61dc484d094c25ac01a4d1dd6911..0000000000000000000000000000000000000000 --- a/car/src/main/java/cz/muni/pa165/car/data/repository/CarComponentPairRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package cz.muni.pa165.car.data.repository; - -import cz.muni.pa165.car.data.model.Car; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository for manipulation with car's components. - */ -@Repository -public interface CarComponentPairRepository extends JpaRepository<Car, Long> {} diff --git a/car/src/main/java/cz/muni/pa165/car/data/repository/CarDriverPairRepository.java b/car/src/main/java/cz/muni/pa165/car/data/repository/CarDriverPairRepository.java deleted file mode 100644 index 4f8aa431f3ba7bef35b04f5ac6070b30c994bc6c..0000000000000000000000000000000000000000 --- a/car/src/main/java/cz/muni/pa165/car/data/repository/CarDriverPairRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package cz.muni.pa165.car.data.repository; - -import cz.muni.pa165.car.data.model.Car; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository for manipulation with car's drivers. - */ -@Repository -public interface CarDriverPairRepository extends JpaRepository<Car, Long> {} diff --git a/car/src/main/java/cz/muni/pa165/car/mapper/CarMapper.java b/car/src/main/java/cz/muni/pa165/car/mapper/CarMapper.java index 44ea6e762f75ad7b8c9d366f46c64dc6441858e8..dd5d13b9f72a9426f880761a81bc296abb75ea87 100644 --- a/car/src/main/java/cz/muni/pa165/car/mapper/CarMapper.java +++ b/car/src/main/java/cz/muni/pa165/car/mapper/CarMapper.java @@ -3,6 +3,8 @@ package cz.muni.pa165.car.mapper; import cz.muni.pa165.car.data.model.Car; import cz.muni.pa165.common_library.dtos.CarRequestDto; import cz.muni.pa165.common_library.dtos.CarResponseDto; +import java.util.ArrayList; +import java.util.HashSet; /** * Class for converting Car object and its Data Transfer Objects. @@ -19,8 +21,8 @@ public class CarMapper { return Car.builder() .id(null) - .components(carRequestDto.getComponentIds()) - .drivers(carRequestDto.getDriverIds()) + .components(new HashSet<>(carRequestDto.getComponentIds())) + .drivers(new HashSet<>(carRequestDto.getDriverIds())) .mainDriverId(carRequestDto.getMainDriverId()) .build(); } @@ -35,10 +37,11 @@ public class CarMapper { return CarResponseDto.builder() .id(car.getId()) - .componentIdsNames(car.getComponents()) - .driverIdsNames(car.getDrivers()) + .componentIdsNames(new ArrayList<>(car.getComponents())) + .driverIdsNames(new ArrayList<>(car.getDrivers())) .mainDriverId(car.getMainDriverId()) .build(); } + } diff --git a/car/src/main/java/cz/muni/pa165/car/restemplate/DbGetter.java b/car/src/main/java/cz/muni/pa165/car/restemplate/DbGetter.java index 61a43c0bd756c1dee35f2ba555a601233821d26d..3ee16541c759402000379439d7206a7f09ad6734 100644 --- a/car/src/main/java/cz/muni/pa165/car/restemplate/DbGetter.java +++ b/car/src/main/java/cz/muni/pa165/car/restemplate/DbGetter.java @@ -1,8 +1,7 @@ package cz.muni.pa165.car.restemplate; -import cz.muni.pa165.component.data.model.CarComponent; -import cz.muni.pa165.driver.data.model.Driver; -import org.springframework.beans.factory.annotation.Autowired; +import cz.muni.pa165.common_library.dtos.CarComponentDto; +import cz.muni.pa165.common_library.dtos.DriverInsightDto; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -13,11 +12,10 @@ import org.springframework.web.client.RestTemplate; @Component public class DbGetter { - @Autowired private static RestTemplate client = new RestTemplate(); private static final String GET_DRIVER_URL = "http://localhost:8083/driver/get/id="; - private static final String GET_COMPONENT_URL = "http://localhost:8084/component?id="; + private static final String GET_COMPONENT_URL = "http://localhost:8084/component/id?componentId="; /** * Get a driver using RestTemplate client. @@ -25,9 +23,9 @@ public class DbGetter { * @param id driver id * @return Driver object */ - public static Driver getDriverFromDb(Long id) { + public static DriverInsightDto getDriverFromDb(Long id) { String url = GET_DRIVER_URL + id; - ResponseEntity<Driver> response = client.getForEntity(url, Driver.class); + ResponseEntity<DriverInsightDto> response = client.getForEntity(url, DriverInsightDto.class); return response.getBody(); } @@ -37,9 +35,9 @@ public class DbGetter { * @param id component id * @return Component object */ - public static CarComponent getComponentFromDb(Long id) { + public static CarComponentDto getComponentFromDb(Long id) { String url = GET_COMPONENT_URL + id; - ResponseEntity<CarComponent> response = client.getForEntity(url, CarComponent.class); + ResponseEntity<CarComponentDto> response = client.getForEntity(url, CarComponentDto.class); return response.getBody(); } diff --git a/car/src/main/java/cz/muni/pa165/car/service/CarComponentPairServiceImpl.java b/car/src/main/java/cz/muni/pa165/car/service/CarComponentPairServiceImpl.java index f0afe6ccf9ef3677214f516a2c6e32136946a6b8..8387e271dcee8a05c1757b6ffe8a068f1547a229 100644 --- a/car/src/main/java/cz/muni/pa165/car/service/CarComponentPairServiceImpl.java +++ b/car/src/main/java/cz/muni/pa165/car/service/CarComponentPairServiceImpl.java @@ -2,13 +2,14 @@ package cz.muni.pa165.car.service; import static cz.muni.pa165.car.restemplate.DbGetter.getComponentFromDb; +import cz.muni.pa165.car.data.model.Car; import cz.muni.pa165.car.data.repository.CarRepository; import cz.muni.pa165.car.mapper.CarMapper; import cz.muni.pa165.common_library.dtos.CarComponentDto; import cz.muni.pa165.common_library.dtos.CarResponseDto; import cz.muni.pa165.common_library.exception.DatabaseException; -import cz.muni.pa165.component.data.model.CarComponent; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; import org.springframework.stereotype.Service; @@ -34,8 +35,13 @@ public class CarComponentPairServiceImpl implements CarComponentPairService { public CarResponseDto addComponent(Long componentId, Long carId) { var car = carRepository.findById(carId).orElseThrow( () -> new DatabaseException("Car not found")); + + if (isComponentInUse(componentId, carId)) { + throw new DatabaseException("Component with id " + componentId + " already in use"); + } var components = car.getComponents(); - components.add(componentId); + CarComponentDto carComponent = getComponentFromDb(componentId); + components.add(carComponent.getId()); car.setComponents(components); carRepository.save(car); return CarMapper.carConverterToDto(car); @@ -45,7 +51,7 @@ public class CarComponentPairServiceImpl implements CarComponentPairService { public CarResponseDto removeComponent(Long componentId, Long carId) { var car = carRepository.findById(carId).orElseThrow( () -> new DatabaseException("Car not found")); - var components = new ArrayList<Long>(); + var components = new HashSet<Long>(); for (Long id : car.getComponents()) { if (!Objects.equals(id, componentId)) { components.add(id); @@ -62,7 +68,7 @@ public class CarComponentPairServiceImpl implements CarComponentPairService { () -> new DatabaseException("Car not found")); var componentDtos = new ArrayList<CarComponentDto>(); for (Long id : car.getComponents()) { - CarComponent carComponent = getComponentFromDb(id); + CarComponentDto carComponent = getComponentFromDb(id); componentDtos.add( new CarComponentDto( carComponent.getId(), @@ -76,4 +82,15 @@ public class CarComponentPairServiceImpl implements CarComponentPairService { return componentDtos; } + private boolean isComponentInUse(Long componentId, Long carId) { + var cars = carRepository.findAll(); + + for (Car car : cars) { + if (car.getComponents().stream() + .anyMatch(x -> x.longValue() == componentId && !Objects.equals(car.getId(), carId))) { + return true; + } + } + return false; + } } diff --git a/car/src/main/java/cz/muni/pa165/car/service/CarDriverPairServiceImpl.java b/car/src/main/java/cz/muni/pa165/car/service/CarDriverPairServiceImpl.java index dabba4a173a72b33faefd6aed346f495597243d5..543d9dc41a8f8c0e2c5809ae530ba7bdaaaceb5c 100644 --- a/car/src/main/java/cz/muni/pa165/car/service/CarDriverPairServiceImpl.java +++ b/car/src/main/java/cz/muni/pa165/car/service/CarDriverPairServiceImpl.java @@ -6,9 +6,10 @@ import cz.muni.pa165.car.data.repository.CarRepository; import cz.muni.pa165.car.mapper.CarMapper; import cz.muni.pa165.common_library.dtos.CarResponseDto; import cz.muni.pa165.common_library.dtos.DriverDto; +import cz.muni.pa165.common_library.dtos.DriverInsightDto; import cz.muni.pa165.common_library.exception.DatabaseException; -import cz.muni.pa165.driver.data.model.Driver; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; import org.springframework.stereotype.Service; @@ -34,9 +35,12 @@ public class CarDriverPairServiceImpl implements CarDriverPairService { public CarResponseDto assignDriverToCar(Long driverId, Long carId) { var car = carRepository.findById(carId).orElseThrow( () -> new DatabaseException("Car not found")); + var drivers = car.getDrivers(); - drivers.add(driverId); + var savedDriver = getDriverFromDb(driverId); + drivers.add(savedDriver.id()); car.setDrivers(drivers); + carRepository.save(car); return CarMapper.carConverterToDto(car); } @@ -45,7 +49,7 @@ public class CarDriverPairServiceImpl implements CarDriverPairService { public CarResponseDto unassignDriverFromCar(Long driverId, Long carId) { var car = carRepository.findById(carId).orElseThrow( () -> new DatabaseException("Car not found")); - var drivers = new ArrayList<Long>(); + var drivers = new HashSet<Long>(); for (Long id : car.getDrivers()) { if (!Objects.equals(id, driverId)) { drivers.add(id); @@ -62,11 +66,11 @@ public class CarDriverPairServiceImpl implements CarDriverPairService { () -> new DatabaseException("Car not found")); var driverDtos = new ArrayList<DriverDto>(); for (Long id : car.getDrivers()) { - Driver driver = getDriverFromDb(id); + DriverInsightDto driver = getDriverFromDb(id); driverDtos.add( - new DriverDto(driver.getId(), - driver.getName(), - driver.getSurname()) + new DriverDto(driver.id(), + driver.name(), + driver.surname()) ); } return driverDtos; @@ -76,7 +80,13 @@ public class CarDriverPairServiceImpl implements CarDriverPairService { public CarResponseDto setMainDriver(Long carId, Long driverId) { var car = carRepository.findById(carId).orElseThrow( () -> new DatabaseException("Car not found")); - car.setMainDriverId(driverId); + + var savedDriver = getDriverFromDb(driverId); + car.setMainDriverId(savedDriver.id()); + + var drivers = car.getDrivers(); + drivers.add(savedDriver.id()); + car.setDrivers(drivers); carRepository.save(car); return CarMapper.carConverterToDto(car); } diff --git a/car/src/main/java/cz/muni/pa165/car/service/CarServiceImpl.java b/car/src/main/java/cz/muni/pa165/car/service/CarServiceImpl.java index 874dbf4a907219b91a5d232c17e6f5dd64113cd9..38f8d647f3621f3baa6413ab6d99339b8f83d58a 100644 --- a/car/src/main/java/cz/muni/pa165/car/service/CarServiceImpl.java +++ b/car/src/main/java/cz/muni/pa165/car/service/CarServiceImpl.java @@ -3,12 +3,15 @@ package cz.muni.pa165.car.service; import static cz.muni.pa165.car.mapper.CarMapper.carConverterToDto; import static cz.muni.pa165.car.mapper.CarMapper.carDtoConverter; +import cz.muni.pa165.car.data.model.Car; import cz.muni.pa165.car.data.repository.CarRepository; import cz.muni.pa165.car.mapper.CarMapper; +import cz.muni.pa165.car.restemplate.DbGetter; import cz.muni.pa165.common_library.dtos.CarRequestDto; import cz.muni.pa165.common_library.dtos.CarResponseDto; import cz.muni.pa165.common_library.exception.DatabaseException; import java.util.List; +import java.util.Objects; import org.springframework.stereotype.Service; @@ -31,6 +34,14 @@ public class CarServiceImpl implements CarService { @Override public CarResponseDto postCar(CarRequestDto carRequestDto) { + + var componentIds = carRequestDto.getComponentIds(); + for (Long componentId : componentIds) { + if (isComponentInUse(componentId)) { + throw new DatabaseException("Component with id " + componentId + " already in use"); + } + DbGetter.getComponentFromDb(componentId); + } return carConverterToDto(carRepository.save(carDtoConverter(carRequestDto))); } @@ -58,4 +69,15 @@ public class CarServiceImpl implements CarService { return "Car with id = " + carId + " deleted!"; } + private boolean isComponentInUse(Long componentId) { + var cars = carRepository.findAll(); + + for (Car car : cars) { + if (car.getComponents().stream() + .anyMatch(x -> x.longValue() == componentId)) { + return true; + } + } + return false; + } } diff --git a/common_library/pom.xml b/common_library/pom.xml index 3faccf9d86604a3d277d80682874eb190f00f2d7..c01b20c9c8ec27c1f8320d5de771b70a9b75a92b 100644 --- a/common_library/pom.xml +++ b/common_library/pom.xml @@ -57,6 +57,11 @@ <artifactId>swagger-annotations</artifactId> <version>1.6.2</version> </dependency> + <dependency> + <groupId>org.apache.httpcomponents.client5</groupId> + <artifactId>httpclient5</artifactId> + <version>5.2.1</version> + </dependency> </dependencies> </project> diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/client/ClientConfig.java b/common_library/src/main/java/cz/muni/pa165/common_library/client/ClientConfig.java index 1008f78988f6293f642dcff7a14e50e151ec8ca4..9cd037e7e21e5cbc37b002ae83095f49db5ea8ed 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/client/ClientConfig.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/client/ClientConfig.java @@ -6,6 +6,9 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +/** + * Custom Rest Template class. + */ @Configuration public class ClientConfig { diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/CarResponseDto.java b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/CarResponseDto.java index ddc8a224d96727bb85e6fa85a460cdd054ec8bc7..93a5a8b57fdd65328ed7f3e7484b929bb6212a4a 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/CarResponseDto.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/CarResponseDto.java @@ -2,13 +2,11 @@ package cz.muni.pa165.common_library.dtos; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.data.util.Pair; - -import java.util.List; /** * Data Transfer object for Car class. diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDriverCarDto.java b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDriverCarDto.java index a950fc9846908df7655d8e9d907bcc5b430eb793..0e635504e632573c917679554c2b16ccd4e31935 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDriverCarDto.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDriverCarDto.java @@ -12,17 +12,12 @@ import lombok.Data; @Builder public class RaceDriverCarDto { - @NotNull @Schema(description = "driver id", example = "1") Long driverId; - @NotNull @Schema(description = "car id", example = "1") Long carId; - @Schema(description = "driver name", example = "Charles Leclerc") - String driverName; - @Schema(description = "drivers position in the race", example = "1") - int position; + Integer position; } diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/exception/BadRequestException.java b/common_library/src/main/java/cz/muni/pa165/common_library/exception/BadRequestException.java new file mode 100644 index 0000000000000000000000000000000000000000..4fd9c87517850fa07a1b72735a1ba73a78ea4825 --- /dev/null +++ b/common_library/src/main/java/cz/muni/pa165/common_library/exception/BadRequestException.java @@ -0,0 +1,11 @@ +package cz.muni.pa165.common_library.exception; + +/** + * Exception when request is not valid. + */ +public class BadRequestException extends RuntimeException { + + public BadRequestException(String message) { + super(message); + } +} diff --git a/common_library/src/main/resources.mv.db b/common_library/src/main/resources.mv.db index ae5c95ed56afac4a5b27f94374b575c6aee30393..1182c1e131cc2956fe8d996155055527cf19a6b7 100644 Binary files a/common_library/src/main/resources.mv.db and b/common_library/src/main/resources.mv.db differ diff --git a/common_library/src/main/resources.trace.db b/common_library/src/main/resources.trace.db index c23aec91212598ef4d254120d1666357f7e0e0b2..1821ae2dbbf3854b6affcf9d2504b39511a2392a 100644 --- a/common_library/src/main/resources.trace.db +++ b/common_library/src/main/resources.trace.db @@ -489,3 +489,146 @@ org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed ( at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:833) +2023-04-16 00:27:08 database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:395) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:125) + at org.h2.mvstore.MVStore.handleException(MVStore.java:3318) + at org.h2.mvstore.MVStore.panic(MVStore.java:593) + at org.h2.mvstore.MVStore.<init>(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.<init>(Store.java:136) + at org.h2.engine.Database.<init>(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:159) + at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:117) + at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80) + at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:330) + at org.springframework.boot.jdbc.EmbeddedDatabaseConnection.isEmbedded(EmbeddedDatabaseConnection.java:168) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateDefaultDdlAutoProvider.getDefaultDdlAuto(HibernateDefaultDdlAutoProvider.java:42) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.lambda$getVendorProperties$1(HibernateJpaConfiguration.java:129) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings.getDdlAuto(HibernateSettings.java:41) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.determineDdlAuto(HibernateProperties.java:118) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.getAdditionalProperties(HibernateProperties.java:87) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.determineHibernateProperties(HibernateProperties.java:80) + at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.getVendorProperties(HibernateJpaConfiguration.java:130) + at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.entityManagerFactory(JpaBaseConfiguration.java:131) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1325) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1132) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:907) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) + at cz.muni.pa165.race.App.main(App.java:28) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 60 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.<init>(MVStore.java:452) + ... 54 more +2023-04-16 00:27:10 database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:395) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:125) + at org.h2.mvstore.MVStore.handleException(MVStore.java:3318) + at org.h2.mvstore.MVStore.panic(MVStore.java:593) + at org.h2.mvstore.MVStore.<init>(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.<init>(Store.java:136) + at org.h2.engine.Database.<init>(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:284) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:177) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:36) + at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:255) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:230) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207) + at org.hibernate.boot.model.relational.Database.<init>(Database.java:44) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:218) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:191) + at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:138) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1348) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1419) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1798) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1748) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1132) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:907) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) + at cz.muni.pa165.race.App.main(App.java:28) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 59 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/diana/pa165/pa165-formula-one-team/common_library/src/main/resources.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.<init>(MVStore.java:452) + ... 53 more diff --git a/component/src/main/java/cz/muni/pa165/component/App.java b/component/src/main/java/cz/muni/pa165/component/App.java index 3ead9f59388d632420db1164711e386a4beb02b2..6509fc53585d232a161f6f2aea8c9aa1291c5299 100644 --- a/component/src/main/java/cz/muni/pa165/component/App.java +++ b/component/src/main/java/cz/muni/pa165/component/App.java @@ -1,16 +1,19 @@ package cz.muni.pa165.component; +import cz.muni.pa165.common_library.exception.RestExceptionHandler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Import; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; /** * Main app. */ -@SpringBootApplication(scanBasePackages = {"cz.muni.pa165.*"}) -@EnableJpaRepositories(basePackages = {"cz.muni.pa165.*"}) -@EntityScan("cz.muni.pa165.*") +@SpringBootApplication +@EnableJpaRepositories(basePackages = {"cz.muni.pa165.component.data.repository"}) +@EntityScan("cz.muni.pa165.component.data.model") +@Import(RestExceptionHandler.class) public class App { public static void main(String[] args) { diff --git a/driver/pom.xml b/driver/pom.xml index 7e77dd7ae46718f8d0e22fa66e176fd91a35c9c1..14d6cbcd6263eadbffc24a42c625dcbde3fc03b1 100644 --- a/driver/pom.xml +++ b/driver/pom.xml @@ -51,6 +51,12 @@ <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> <properties> diff --git a/driver/src/main/java/cz/muni/pa165/driver/App.java b/driver/src/main/java/cz/muni/pa165/driver/App.java index 07f54711f763b4f4ffe88a7f3447a3ad85fb5259..d506128e67d67d4270ed020b3d05a4edb9567a2d 100644 --- a/driver/src/main/java/cz/muni/pa165/driver/App.java +++ b/driver/src/main/java/cz/muni/pa165/driver/App.java @@ -1,8 +1,10 @@ package cz.muni.pa165.driver; +import cz.muni.pa165.common_library.exception.RestExceptionHandler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Import; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; /** @@ -11,6 +13,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EnableJpaRepositories(basePackages = {"cz.muni.pa165.driver.data.repository"}) @EntityScan(basePackages = {"cz.muni.pa165.driver.data.model"}) +@Import(RestExceptionHandler.class) public class App { public static void main(String[] args) { diff --git a/driver/src/main/resources/application.yml b/driver/src/main/resources/application.yml index 421c1494b0c391b664d3c8ef1495b200c904a8ea..5506c8f217a43b34f91fbd7999c8d5bb0c2fbae6 100644 --- a/driver/src/main/resources/application.yml +++ b/driver/src/main/resources/application.yml @@ -16,7 +16,7 @@ spring: hibernate: ddl-auto: update datasource: - url: jdbc:h2:.\common_library\src\main\resources;MODE=PostgreSQL + url: jdbc:h2:mem:driver;MODE=PostgreSQL driverClassName: org.h2.Driver username: admin password: admin diff --git a/driver/src/test/java/cz/muni/pa165/driver/rest/DriverControllerItTest.java b/driver/src/test/java/cz/muni/pa165/driver/rest/DriverControllerItTest.java new file mode 100644 index 0000000000000000000000000000000000000000..13814dafebd455689e3caa59be35518bb2b68a8a --- /dev/null +++ b/driver/src/test/java/cz/muni/pa165/driver/rest/DriverControllerItTest.java @@ -0,0 +1,38 @@ +package cz.muni.pa165.driver.rest; + +import cz.muni.pa165.driver.data.model.Driver; +import cz.muni.pa165.driver.data.repository.DriverRepository; +import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@DataJpaTest +class DriverControllerItTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private DriverRepository driverRepository; + + @Test + public void testSave() { + Driver driver = Driver.builder() + .name("name") + .surname("surname") + .nationality("nationality") + .characteristics(Map.of()).build(); + + Driver savedDriver = driverRepository.save(driver); + + Assertions.assertEquals(savedDriver, driver); + Assertions.assertEquals(entityManager.find(Driver.class, 1L).getId(), 1); + } + +} diff --git a/race/pom.xml b/race/pom.xml index 56af86d09bbf7c3e113baabccc3392e550abf1b9..266c650e014f8a1ddca70c7dbf43f2ba0338defa 100644 --- a/race/pom.xml +++ b/race/pom.xml @@ -32,18 +32,6 @@ <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency> - <dependency> - <groupId>fi.muni</groupId> - <artifactId>car</artifactId> - <version>0.0.1-SNAPSHOT</version> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>fi.muni</groupId> - <artifactId>driver</artifactId> - <version>0.0.1-SNAPSHOT</version> - <scope>compile</scope> - </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> diff --git a/race/src/main/java/cz/muni/pa165/race/App.java b/race/src/main/java/cz/muni/pa165/race/App.java index 47715a6ff43b72c5f0b5f033eee3fe96eb83834c..874755e90d6b2d58231719d80c9f79ee6e25937f 100644 --- a/race/src/main/java/cz/muni/pa165/race/App.java +++ b/race/src/main/java/cz/muni/pa165/race/App.java @@ -1,9 +1,8 @@ package cz.muni.pa165.race; -import cz.muni.pa165.car.data.model.Car; + import cz.muni.pa165.common_library.client.ClientConfig; import cz.muni.pa165.common_library.exception.RestExceptionHandler; -import cz.muni.pa165.driver.data.model.Driver; import cz.muni.pa165.race.data.model.Race; import cz.muni.pa165.race.data.model.Season; import org.springframework.boot.SpringApplication; @@ -19,7 +18,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableJpaRepositories(basePackages = "cz.muni.pa165.race.data.repository") @EnableTransactionManagement -@EntityScan(basePackageClasses = {Race.class, Season.class, Car.class, Driver.class}) +@EntityScan(basePackageClasses = {Race.class, Season.class}) @Import({RestExceptionHandler.class, ClientConfig.class}) public class App { diff --git a/race/src/main/java/cz/muni/pa165/race/data/model/Race.java b/race/src/main/java/cz/muni/pa165/race/data/model/Race.java index 16541e30267d56edc756d70f91a0800ca53e0abb..dba10990acb1741bf1f97e1432d46d74bac7c17e 100644 --- a/race/src/main/java/cz/muni/pa165/race/data/model/Race.java +++ b/race/src/main/java/cz/muni/pa165/race/data/model/Race.java @@ -1,19 +1,15 @@ package cz.muni.pa165.race.data.model; -import cz.muni.pa165.car.data.model.Car; import cz.muni.pa165.common_library.dtos.Location; -import cz.muni.pa165.driver.data.model.Driver; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.Max; @@ -45,11 +41,11 @@ public class Race implements Serializable { private RaceInfo raceInfo; @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "driver_info_one_id") + @JoinColumn(name = "driver_one_id") private RaceDriverinfo driver1; @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "driver_info_two_id") + @JoinColumn(name = "driver_two_id") private RaceDriverinfo driver2; /** @@ -67,17 +63,13 @@ public class Race implements Serializable { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "driver_one_id") - private Driver driver; + private Long driverId; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "car_one_id") - private Car car; + private Long carId; @Min(1) @Max(20) - private int finalPosition; + private Integer finalPosition; } /** diff --git a/race/src/main/java/cz/muni/pa165/race/data/repository/CarRepository.java b/race/src/main/java/cz/muni/pa165/race/data/repository/CarRepository.java deleted file mode 100644 index b0f8e24736e5d946c712c7caa9a2ee8fcf763c03..0000000000000000000000000000000000000000 --- a/race/src/main/java/cz/muni/pa165/race/data/repository/CarRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package cz.muni.pa165.race.data.repository; - -import cz.muni.pa165.car.data.model.Car; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository for car. - */ -@Repository -public interface CarRepository extends JpaRepository<Car, Long> { - -} diff --git a/race/src/main/java/cz/muni/pa165/race/data/repository/DriverRepository.java b/race/src/main/java/cz/muni/pa165/race/data/repository/DriverRepository.java deleted file mode 100644 index c5738d33a2066923df8aed853f8efb0ed2504c03..0000000000000000000000000000000000000000 --- a/race/src/main/java/cz/muni/pa165/race/data/repository/DriverRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package cz.muni.pa165.race.data.repository; - - -import cz.muni.pa165.driver.data.model.Driver; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Driver repository. - */ -@Repository -public interface DriverRepository extends JpaRepository<Driver, Long> { -} diff --git a/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java b/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java index 6c9f7ce68d5a82f47cbea4cc8750a87508bb973f..b1bdd7be9675172e847cfbbfd19ab69e1fb066e5 100644 --- a/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java +++ b/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java @@ -21,4 +21,9 @@ public interface RaceRepository extends JpaRepository<Race, Long> { + "WHERE ri.location = :location AND (do.id = :driverId OR dt.id = :driverId)") List<Race> findAllRacesOfDriverInLocation(@Param("location") Location raceLocation, @Param("driverId") long driverId); + + @Query("SELECT r FROM Race r" + + " JOIN r.raceInfo ri " + + "WHERE ri.location = :location") + List<Race> findRacesByLocation(@Param("location") Location raceLocation); } diff --git a/race/src/main/java/cz/muni/pa165/race/rest/RaceController.java b/race/src/main/java/cz/muni/pa165/race/rest/RaceController.java index 24ce9dd85f436d57519406d49c03ef366d6e422a..907c1066bfcde52f66c95b7c435817bd4d882bde 100644 --- a/race/src/main/java/cz/muni/pa165/race/rest/RaceController.java +++ b/race/src/main/java/cz/muni/pa165/race/rest/RaceController.java @@ -1,11 +1,13 @@ package cz.muni.pa165.race.rest; +import cz.muni.pa165.common_library.dtos.Location; import cz.muni.pa165.common_library.dtos.RaceDto; -import cz.muni.pa165.race.service.RaceService; +import cz.muni.pa165.race.service.RaceServiceI; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import java.util.List; +import java.util.Set; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -26,9 +28,9 @@ import org.springframework.web.bind.annotation.RestController; @Validated public class RaceController { - RaceService raceService; + RaceServiceI raceService; - public RaceController(RaceService raceService) { + public RaceController(RaceServiceI raceService) { this.raceService = raceService; } @@ -42,14 +44,14 @@ public class RaceController { @Operation(summary = "Delete a race") @DeleteMapping(path = "/", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<String> deleteRace(@Valid @RequestParam long raceId) { + public ResponseEntity<String> deleteRace(@Valid @RequestParam Long raceId) { return ResponseEntity.ok(raceService.deleteRace(raceId)); } @Operation(summary = "Get a race") @GetMapping(path = "/id", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<RaceDto> getRace(@Valid @RequestParam long raceId) { + public ResponseEntity<RaceDto> getRace(@Valid @RequestParam Long raceId) { return ResponseEntity.ok(raceService.findRaceById(raceId)); } @@ -63,16 +65,41 @@ public class RaceController { @Operation(summary = "Assign driver as driver number one for a race") @PatchMapping(path = "/assignDriverOne", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<String> assignDriverOne(@RequestParam long driverOneId, - @RequestParam long raceId) { - return ResponseEntity.ok(raceService.assignDriverOne(driverOneId, raceId)); + public ResponseEntity<RaceDto> assignDriverOne(@RequestParam Long driverOneId, + @RequestParam Long raceId, + @RequestParam Long carId) { + return ResponseEntity.ok(raceService.assignDriverOne(driverOneId, raceId, carId)); } @Operation(summary = "Assign driver as a driver number two for a race") @PatchMapping(path = "/assignDriverTwo", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<String> assignDriverTwo(@RequestParam long driverTwoId, - @RequestParam long raceId) { - return ResponseEntity.ok(raceService.assignDriverTwo(driverTwoId, raceId)); + public ResponseEntity<RaceDto> assignDriverTwo(@RequestParam Long driverTwoId, + @RequestParam Long raceId, + @RequestParam Long carId) { + return ResponseEntity.ok(raceService.assignDriverTwo(driverTwoId, raceId, carId)); + } + + @Operation(summary = "Assign position for driver two") + @PatchMapping(path = "/assignPointsDriverTwo", + produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<RaceDto> assignPositionDriverTwo(@RequestParam Long raceId, + @RequestParam Integer position) { + return ResponseEntity.ok(raceService.assignPositionForDriverTwo(raceId, position)); + } + + @Operation(summary = "Assign position for driver two") + @PatchMapping(path = "/assignPointsDriverOne", + produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<RaceDto> assignPositionDriverOne(@RequestParam Long raceId, + @RequestParam Integer position) { + return ResponseEntity.ok(raceService.assignPositionForDriverOne(raceId, position)); + } + + @Operation(summary = "get races") + @GetMapping(path = "/findMostSuitableDriversForLocation") + public ResponseEntity<Set<Long>> getMostSuitableDriversForLocation( + @RequestParam Location location) { + return ResponseEntity.ok(raceService.findMostSuitableDriver(location)); } } diff --git a/race/src/main/java/cz/muni/pa165/race/rest/SeasonController.java b/race/src/main/java/cz/muni/pa165/race/rest/SeasonController.java index b3ced6adf195628df009699e0e7459d7358c65ea..18526b60120d6ef8529b817dddfa6fabafe8a25a 100644 --- a/race/src/main/java/cz/muni/pa165/race/rest/SeasonController.java +++ b/race/src/main/java/cz/muni/pa165/race/rest/SeasonController.java @@ -1,7 +1,7 @@ package cz.muni.pa165.race.rest; import cz.muni.pa165.common_library.dtos.SeasonDto; -import cz.muni.pa165.race.service.SeasonServiceInterface; +import cz.muni.pa165.race.service.SeasonServiceI; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import java.util.List; @@ -25,9 +25,9 @@ import org.springframework.web.bind.annotation.RestController; @Validated public class SeasonController { - SeasonServiceInterface seasonService; + SeasonServiceI seasonService; - public SeasonController(SeasonServiceInterface seasonService) { + public SeasonController(SeasonServiceI seasonService) { this.seasonService = seasonService; } diff --git a/race/src/main/java/cz/muni/pa165/race/service/PointsUtil.java b/race/src/main/java/cz/muni/pa165/race/service/PointsUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..22e9f8dd19feed47eb2395281fe3db6aa23c0381 --- /dev/null +++ b/race/src/main/java/cz/muni/pa165/race/service/PointsUtil.java @@ -0,0 +1,32 @@ +package cz.muni.pa165.race.service; + +import java.util.HashMap; +import java.util.Map; + +/** + * Utility for points per position. + */ +public class PointsUtil { + + /** + * Map with position and corresponding points. + */ + public Map<Integer, Integer> points; + + /** + * Constructor. + */ + public PointsUtil() { + points = new HashMap<>(); + points.put(1, 25); + points.put(2, 18); + points.put(3, 15); + points.put(4, 12); + points.put(5, 10); + points.put(6, 8); + points.put(7, 6); + points.put(8, 4); + points.put(9, 2); + points.put(10, 1); + } +} diff --git a/race/src/main/java/cz/muni/pa165/race/service/RaceService.java b/race/src/main/java/cz/muni/pa165/race/service/RaceService.java index fc1cae9f879e8433f8d848c5e4d9e63a61ae013f..48797427e5a4ea415d066893b00fbc75636b3fbc 100644 --- a/race/src/main/java/cz/muni/pa165/race/service/RaceService.java +++ b/race/src/main/java/cz/muni/pa165/race/service/RaceService.java @@ -1,15 +1,21 @@ package cz.muni.pa165.race.service; -import cz.muni.pa165.car.data.model.Car; +import cz.muni.pa165.common_library.dtos.CarResponseDto; +import cz.muni.pa165.common_library.dtos.DriverDto; +import cz.muni.pa165.common_library.dtos.Location; import cz.muni.pa165.common_library.dtos.RaceDriverCarDto; import cz.muni.pa165.common_library.dtos.RaceDto; +import cz.muni.pa165.common_library.exception.BadRequestException; import cz.muni.pa165.common_library.exception.DatabaseException; -import cz.muni.pa165.driver.data.model.Driver; import cz.muni.pa165.race.data.model.Race; -import cz.muni.pa165.race.data.repository.CarRepository; -import cz.muni.pa165.race.data.repository.DriverRepository; import cz.muni.pa165.race.data.repository.RaceRepository; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @@ -19,20 +25,17 @@ import org.springframework.web.client.RestTemplate; */ // TODO chybnú hlášku spraviť konštantu @Service -public class RaceService { +public class RaceService implements RaceServiceI { + + PointsUtil pointsUtil = new PointsUtil(); RaceRepository raceRepository; - CarRepository carRepository; - DriverRepository driverRepository; @Autowired RestTemplate client; - RaceService(RaceRepository raceRepository, CarRepository carRepository, - DriverRepository driverRepository) { + RaceService(RaceRepository raceRepository) { this.raceRepository = raceRepository; - this.carRepository = carRepository; - this.driverRepository = driverRepository; } /** @@ -59,29 +62,44 @@ public class RaceService { /** * Assigns driver one. */ - public String assignDriverOne(Long driverId, Long raceId) { - var driver = driverRepository.findById(driverId) - .orElseThrow(() -> new DatabaseException("Driver not found")); + public RaceDto assignDriverOne(Long driverId, Long raceId, Long carId) { var race = raceRepository.findById(raceId) .orElseThrow(() -> new DatabaseException("Race not found")); - race.getDriver1().setDriver(driver); - raceRepository.save(race); - return "Driver with id: " + driverId + "was succesfully assigned to race with id: " - + raceId + " as driver one"; + + var driver = getDriver(driverId); + if (race.getDriver2() != null && Objects.equals(race.getDriver2().getDriverId(), driverId)) { + throw new BadRequestException("Driver already assigned to the race as driver two"); + } + + var car = getCar(carId); + if (race.getDriver2() != null && Objects.equals(race.getDriver2().getCarId(), carId)) { + throw new BadRequestException("Car is already assigned to the race for driver two"); + } + race.getDriver1().setDriverId(driver.getId()); + race.getDriver1().setCarId(car.getId()); + return convertRace(raceRepository.save(race)); } /** * Assigns driver two. */ - public String assignDriverTwo(Long driverId, Long raceId) { - var driver = driverRepository.findById(driverId) - .orElseThrow(() -> new DatabaseException("Driver not found")); + public RaceDto assignDriverTwo(Long driverId, Long raceId, Long carId) { var race = raceRepository.findById(raceId) .orElseThrow(() -> new DatabaseException("Race not found")); - race.getDriver2().setDriver(driver); - raceRepository.save(race); - return "Driver with id: " + driverId + "was succesfully assigned to race with id: " - + raceId + " as driver two"; + + var driver = getDriver(driverId); + if (race.getDriver1() != null && Objects.equals(race.getDriver1().getDriverId(), driverId)) { + throw new BadRequestException("Driver already assigned to the race as driver one"); + } + var car = getCar(carId); + if (race.getDriver1() != null && Objects.equals(race.getDriver1().getCarId(), carId)) { + throw new BadRequestException("Car is already assigned to the race for driver two"); + } + + race.getDriver2().setDriverId(driver.getId()); + race.getDriver2().setCarId(car.getId()); + var a = convertRace(raceRepository.save(race)); + return a; } /** @@ -105,6 +123,75 @@ public class RaceService { return raceRepository.findAll().stream().map(this::convertRace).toList(); } + /** + * Assigns positions for driver number two. + * + * @param raceId race id. + * @param position position of driver two. + * @return updated race. + */ + public RaceDto assignPositionForDriverTwo(Long raceId, Integer position) { + var race = + raceRepository.findById(raceId).orElseThrow(() -> new DatabaseException("Race not found")); + race.getDriver2().setFinalPosition(position); + return convertRace(raceRepository.save(race)); + } + + /** + * Assigns positions for driver number one. + * + * @param raceId race id. + * @param position position of driver one. + * @return updated race. + */ + public RaceDto assignPositionForDriverOne(Long raceId, Integer position) { + var race = + raceRepository.findById(raceId).orElseThrow(() -> new DatabaseException("Race not found")); + race.getDriver2().setFinalPosition(position); + return convertRace(raceRepository.save(race)); + } + + /** + * Finds most suitable drivers for given location. + * + * @param location location of the race. + * @return set if ids of most suitable drivers for given location. + */ + public Set<Long> findMostSuitableDriver(Location location) { + var races = raceRepository.findRacesByLocation(location); + Map<Long, Integer> driverWithPoints = new HashMap<>(); + + for (Race race : races) { + updatePointsForDriver(race.getDriver1(), driverWithPoints); + updatePointsForDriver(race.getDriver2(), driverWithPoints); + } + + var max = Collections.max(driverWithPoints.values()); + Set<Long> drivers = new HashSet<>(); + for (Map.Entry<Long, Integer> entry : driverWithPoints.entrySet()) { + if (Objects.equals(entry.getValue(), max)) { + drivers.add(entry.getKey()); + } + } + return drivers; + } + + private void updatePointsForDriver(Race.RaceDriverinfo driverinfo, + Map<Long, Integer> driverWithPoints) { + if (driverinfo == null || driverinfo.getDriverId() == null) { + return; + } + + Integer points; + if (driverinfo.getFinalPosition() != null) { + points = pointsUtil.points.get(driverinfo.getFinalPosition()); + } else { + points = 0; + } + + driverWithPoints.merge(driverinfo.getDriverId(), points, Integer::sum); + } + private Race convertRaceDto(RaceDto raceDto) { var race = Race.builder() .id(raceDto.getId()) @@ -122,17 +209,21 @@ public class RaceService { if (raceDto.getDriverOne() != null) { race.setDriver1(Race.RaceDriverinfo .builder() - .driver(getDriver(raceDto.getDriverOne())) - .car(getCar(raceDto.getDriverOne())) + .driverId(raceDto.getDriverOne().getDriverId()) + .carId(raceDto.getDriverOne().getCarId()) .build()); + } else { + race.setDriver1(Race.RaceDriverinfo.builder().build()); } if (raceDto.getDriverTwo() != null) { race.setDriver2(Race.RaceDriverinfo .builder() - .driver(getDriver(raceDto.getDriverTwo())) - .car(getCar(raceDto.getDriverTwo())) + .driverId(raceDto.getDriverTwo().getDriverId()) + .carId(raceDto.getDriverTwo().getCarId()) .build()); + } else { + race.setDriver2(Race.RaceDriverinfo.builder().build()); } return race; @@ -147,35 +238,30 @@ public class RaceService { .prizePool(race.getRaceInfo().getPrizePool()) .build()) .build(); - if (race.getDriver1() != null && race.getDriver1().getCar() != null) { + if (race.getDriver1() != null) { raceDto.setDriverOne(RaceDriverCarDto.builder() - .carId(race.getDriver1().getCar().getId()) - .driverId(race.getDriver1().getId()) - .driverName(race.getDriver1().getDriver().getName() - + " " + race.getDriver1().getDriver().getSurname()) + .carId(race.getDriver1().getCarId()) + .driverId(race.getDriver1().getDriverId()) .build()); } - if (race.getDriver2() != null && race.getDriver2().getCar() != null) { + if (race.getDriver2() != null) { raceDto.setDriverTwo(RaceDriverCarDto.builder() - .carId(race.getDriver2().getCar().getId()) - .driverId(race.getDriver2().getId()) - .driverName(race.getDriver2().getDriver().getName() - + " " + race.getDriver2().getDriver().getSurname()) + .carId(race.getDriver2().getCarId()) + .driverId(race.getDriver2().getDriverId()) .build()); } return raceDto; } - - private Driver getDriver(RaceDriverCarDto driverCarDto) { - return driverRepository.findById(driverCarDto.getDriverId()).orElseThrow( - () -> new DatabaseException("Something went wrong when" - + "finding the driver with id: " + driverCarDto.getDriverId() + " in the database.")); + private DriverDto getDriver(Long driverId) { + var response = + client.getForEntity("http://localhost:8083/driver/get/id=" + driverId, DriverDto.class); + return response.getBody(); } - private Car getCar(RaceDriverCarDto driverCarDto) { - return carRepository.findById(driverCarDto.getCarId()).orElseThrow( - () -> new DatabaseException("Something went wrong when" - + "finding the car with id: " + driverCarDto.getCarId() + " in the database.")); + private CarResponseDto getCar(Long carId) { + var response = + client.getForEntity("http://localhost:8082/car/?carId=" + carId, CarResponseDto.class); + return response.getBody(); } } diff --git a/race/src/main/java/cz/muni/pa165/race/service/RaceServiceI.java b/race/src/main/java/cz/muni/pa165/race/service/RaceServiceI.java new file mode 100644 index 0000000000000000000000000000000000000000..55e92823da8ac08e19eae21e20581b8374a23bb0 --- /dev/null +++ b/race/src/main/java/cz/muni/pa165/race/service/RaceServiceI.java @@ -0,0 +1,30 @@ +package cz.muni.pa165.race.service; + +import cz.muni.pa165.common_library.dtos.Location; +import cz.muni.pa165.common_library.dtos.RaceDto; +import java.util.List; +import java.util.Set; + +/** + * Race service interface. + */ +public interface RaceServiceI { + + RaceDto postRace(RaceDto raceDto); + + RaceDto findRaceById(Long raceId); + + List<RaceDto> findRaces(); + + String deleteRace(Long raceId); + + RaceDto assignDriverOne(Long driverId, Long raceId, Long carId); + + RaceDto assignDriverTwo(Long driverId, Long raceId, Long carId); + + Set<Long> findMostSuitableDriver(Location location); + + RaceDto assignPositionForDriverTwo(Long raceId, Integer position); + + RaceDto assignPositionForDriverOne(Long raceId, Integer position); +} diff --git a/race/src/main/java/cz/muni/pa165/race/service/SeasonService.java b/race/src/main/java/cz/muni/pa165/race/service/SeasonService.java index a625082e7da5bc751f85052ff2c79fa6bf1b9c45..78670308be1f9f75ec5a07814ebf7bb58841bf21 100644 --- a/race/src/main/java/cz/muni/pa165/race/service/SeasonService.java +++ b/race/src/main/java/cz/muni/pa165/race/service/SeasonService.java @@ -15,7 +15,7 @@ import org.springframework.stereotype.Service; * Season service. */ @Service -public class SeasonService implements SeasonServiceInterface { +public class SeasonService implements SeasonServiceI { @Autowired SeasonRepository seasonRepository; diff --git a/race/src/main/java/cz/muni/pa165/race/service/SeasonServiceInterface.java b/race/src/main/java/cz/muni/pa165/race/service/SeasonServiceI.java similarity index 89% rename from race/src/main/java/cz/muni/pa165/race/service/SeasonServiceInterface.java rename to race/src/main/java/cz/muni/pa165/race/service/SeasonServiceI.java index 80da12d7a9743d1a060d9e1a1ea92d1514c14eff..004dc30a05f931574772f302c4081bf80cfac28f 100644 --- a/race/src/main/java/cz/muni/pa165/race/service/SeasonServiceInterface.java +++ b/race/src/main/java/cz/muni/pa165/race/service/SeasonServiceI.java @@ -6,7 +6,7 @@ import java.util.List; /** * Interface for season service. */ -public interface SeasonServiceInterface { +public interface SeasonServiceI { SeasonDto postSeason(SeasonDto seasonDto);