From 5c0b157414929fd17b60a0850e38bb38cfa9c2e1 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Sat, 11 May 2024 02:14:06 +0700 Subject: [PATCH] !refactored models, repositories, services and controllers --- server/build.gradle | 2 +- .../picker/aspect/UserMetricsAspect.java | 26 +++--- .../dragonestia/picker/config/TestConfig.java | 23 +++--- .../picker/controller/AccountsController.java | 39 +++++---- .../picker/controller/EntityController.java | 31 +++---- .../controller/EntityRoomController.java | 34 +++----- .../ExceptionHandlerController.java | 78 +----------------- .../picker/controller/InstanceController.java | 56 ++++++------- .../picker/controller/RoomController.java | 68 +++++++--------- .../controller/RoomPickerController.java | 6 +- .../controller/graphql/GraphqlController.java | 20 ++--- .../graphql/object/ObjectEntity.java | 4 +- .../graphql/object/ObjectInstance.java | 4 +- .../controller/graphql/object/ObjectRoom.java | 8 +- .../controller/response/ResponseObject.java | 19 +++++ .../response/RoomPickerInfoResponse.java | 3 + .../AdminAccountMutationException.java | 8 ++ .../exception/AlreadyExistsException.java | 19 +++++ ...ConflictingPersistParametersException.java | 19 +++++ .../exception/DoesNotExistsException.java | 19 +++++ .../exception/InvalidIdentifierException.java | 14 ++++ .../exception/NoRoomsAvailableException.java | 10 +++ .../exception/RoomAreFullException.java | 11 +++ .../picker/model/account/Account.java | 76 +++-------------- .../picker/model/account/AccountId.java | 42 ++++++++++ .../picker/model/entity/Entity.java | 36 +++------ .../picker/model/entity/EntityId.java | 42 ++++++++++ .../picker/model/factory/RoomFactory.java | 19 ----- .../picker/model/instance/Instance.java | 48 +++-------- .../picker/model/instance/InstanceId.java | 53 ++++++++++++ .../model/instance/type/PickingMethod.java | 7 ++ .../dragonestia/picker/model/room/Room.java | 81 +++---------------- .../dragonestia/picker/model/room/RoomId.java | 54 +++++++++++++ .../model/room/factory/RoomFactory.java | 16 ++++ .../picker/repository/EntityRepository.java | 13 +-- .../picker/repository/InstanceRepository.java | 9 ++- .../picker/repository/RoomRepository.java | 19 ++--- .../repository/impl/ContainerRepository.java | 21 ++--- .../repository/impl/EntityRepositoryImpl.java | 42 +++++----- .../impl/InstanceRepositoryImpl.java | 13 +-- .../repository/impl/RoomRepositoryImpl.java | 45 ++++++----- .../impl/container/InstanceContainer.java | 50 ++++++------ .../impl/container/RoomContainer.java | 6 +- .../impl/picker/LeastPickedPicker.java | 10 +-- .../repository/impl/picker/RoomPicker.java | 2 +- .../repository/impl/picker/RoomWrapper.java | 4 +- .../impl/picker/RoundRobinPicker.java | 8 +- .../impl/picker/SequentialFillingPicker.java | 10 +-- .../picker/service/AccountService.java | 12 +-- .../picker/service/EntityService.java | 14 ++-- .../picker/service/InstanceService.java | 9 ++- .../picker/service/RoomService.java | 18 ++--- .../service/impl/AccountServiceImpl.java | 22 ++--- .../service/impl/EntityServiceImpl.java | 19 ++--- .../service/impl/InstanceServiceImpl.java | 15 ++-- .../picker/service/impl/RoomServiceImpl.java | 50 +++++------- .../picker/storage/impl/FileStorageImpl.java | 12 +-- .../picker/config/FillingNodesConfig.java | 2 +- .../picker/picker/LeastPickedTests.java | 4 +- .../picker/picker/RoundRobinTests.java | 2 +- .../picker/picker/SequentialFillingTests.java | 4 +- .../picker/service/InstanceServiceTests.java | 4 +- .../picker/service/RoomServiceTests.java | 10 +-- 63 files changed, 741 insertions(+), 703 deletions(-) create mode 100644 server/src/main/java/ru/dragonestia/picker/controller/response/ResponseObject.java create mode 100644 server/src/main/java/ru/dragonestia/picker/controller/response/RoomPickerInfoResponse.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/AdminAccountMutationException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/AlreadyExistsException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/ConflictingPersistParametersException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/DoesNotExistsException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/InvalidIdentifierException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/NoRoomsAvailableException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/exception/RoomAreFullException.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/account/AccountId.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/entity/EntityId.java delete mode 100644 server/src/main/java/ru/dragonestia/picker/model/factory/RoomFactory.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/instance/InstanceId.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/instance/type/PickingMethod.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/room/RoomId.java create mode 100644 server/src/main/java/ru/dragonestia/picker/model/room/factory/RoomFactory.java diff --git a/server/build.gradle b/server/build.gradle index f2e5f49..46fb14b 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -11,7 +11,7 @@ configurations { } dependencies { - implementation project(":client-api") + //implementation project(":client-api") developmentOnly("org.springframework.boot:spring-boot-devtools") implementation 'org.springframework.boot:spring-boot-starter-aop' implementation 'org.springframework.boot:spring-boot-starter-security' diff --git a/server/src/main/java/ru/dragonestia/picker/aspect/UserMetricsAspect.java b/server/src/main/java/ru/dragonestia/picker/aspect/UserMetricsAspect.java index b76d980..71bf29c 100644 --- a/server/src/main/java/ru/dragonestia/picker/aspect/UserMetricsAspect.java +++ b/server/src/main/java/ru/dragonestia/picker/aspect/UserMetricsAspect.java @@ -57,30 +57,30 @@ public class UserMetricsAspect { @After(value = "execution(void ru.dragonestia.picker.repository.InstanceRepository.create(ru.dragonestia.picker.model.instance.Instance)) && args(instance)", argNames = "instance") void onCreateNode(Instance instance) { - var nodeId = instance.getIdentifier(); - var gauge = Gauge.builder("roompicker_node_users_total", () -> data.get(nodeId).users()) - .tag("nodeId", nodeId) + var nodeId = instance.getId(); + var gauge = Gauge.builder("roompicker_node_users_total", () -> data.get(nodeId.getValue()).users()) + .tag("nodeId", nodeId.getValue()) .register(meterRegistry); var counter = Counter.builder("roompicker_picks") - .tag("nodeId", nodeId) + .tag("nodeId", nodeId.getValue()) .baseUnit("1s") .register(meterRegistry); - var lockedGauge = Gauge.builder("roompicker_locked_rooms", () -> data.get(nodeId).locked()) - .tag("nodeId", nodeId) + var lockedGauge = Gauge.builder("roompicker_locked_rooms", () -> data.get(nodeId.getValue()).locked()) + .tag("nodeId", nodeId.getValue()) .register(meterRegistry); - var roomsGauge = Gauge.builder("roompicker_rooms", () -> roomRepository.all(instance).size()) - .tag("nodeId", nodeId) + var roomsGauge = Gauge.builder("roompicker_rooms", () -> roomRepository.all(instance.getId()).size()) + .tag("nodeId", nodeId.getValue()) .register(meterRegistry); - data.put(nodeId, new NodeData(gauge, new AtomicInteger(0), counter, new AtomicInteger(0), lockedGauge, roomsGauge)); + data.put(nodeId.getValue(), new NodeData(gauge, new AtomicInteger(0), counter, new AtomicInteger(0), lockedGauge, roomsGauge)); } @After(value = "execution(* ru.dragonestia.picker.repository.InstanceRepository.delete(ru.dragonestia.picker.model.instance.Instance)) && args(instance)", argNames = "instance") void onDeleteNode(Instance instance) { - var data = this.data.remove(instance.getIdentifier()); + var data = this.data.remove(instance.getId().getValue()); meterRegistry.remove(data.usersGauge()); meterRegistry.remove(data.picksPerMinute()); @@ -90,17 +90,17 @@ public class UserMetricsAspect { @AfterReturning(value = "execution(* ru.dragonestia.picker.repository.RoomRepository.pick(ru.dragonestia.picker.model.instance.Instance, *)) && args(instance, ..)", argNames = "instance") void onPickRoom(Instance instance) { - data.get(instance.getIdentifier()).picksPerMinute().increment(); + data.get(instance.getId().getValue()).picksPerMinute().increment(); } @Scheduled(fixedDelay = 3_000) void updateUserMetrics() { - entityRepository.countEntitiesForNodes().forEach((nodeId, users) -> { + entityRepository.countEntitiesForInstances().forEach((nodeId, users) -> { Optional.ofNullable(data.get(nodeId)).ifPresent(node -> node.users().set(users)); }); containerRepository.all().forEach(nodeContainer -> { - var locked = data.get(nodeContainer.getInstance().getIdentifier()).locked(); + var locked = data.get(nodeContainer.getInstance().getId().getValue()).locked(); locked.set(0); nodeContainer.allRooms().forEach(roomContainer -> { diff --git a/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java b/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java index 99b67d4..40c7c39 100644 --- a/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java +++ b/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java @@ -10,15 +10,14 @@ import org.springframework.context.annotation.Profile; import org.springframework.lang.NonNull; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import ru.dragonestia.picker.api.model.node.PickingMethod; -import ru.dragonestia.picker.api.model.room.IRoom; -import ru.dragonestia.picker.api.repository.type.NodeIdentifier; -import ru.dragonestia.picker.api.repository.type.RoomIdentifier; -import ru.dragonestia.picker.api.repository.type.EntityIdentifier; import ru.dragonestia.picker.interceptor.DebugInterceptor; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.instance.Instance; import ru.dragonestia.picker.model.entity.Entity; -import ru.dragonestia.picker.model.factory.RoomFactory; +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.instance.type.PickingMethod; +import ru.dragonestia.picker.model.room.RoomId; +import ru.dragonestia.picker.model.room.factory.RoomFactory; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.repository.InstanceRepository; import ru.dragonestia.picker.repository.EntityRepository; @@ -46,9 +45,9 @@ public class TestConfig implements WebMvcConfigurer { @Bean void createInstances() { - createInstanceWithContent(new Instance(NodeIdentifier.of("game-servers"), PickingMethod.ROUND_ROBIN, false)); - createInstanceWithContent(new Instance(NodeIdentifier.of("game-lobbies"), PickingMethod.LEAST_PICKED, false)); - createInstanceWithContent(new Instance(NodeIdentifier.of("hub"), PickingMethod.SEQUENTIAL_FILLING, false)); + createInstanceWithContent(new Instance(InstanceId.of("game-servers"), PickingMethod.ROUND_ROBIN, false)); + createInstanceWithContent(new Instance(InstanceId.of("game-lobbies"), PickingMethod.LEAST_PICKED, false)); + createInstanceWithContent(new Instance(InstanceId.of("hub"), PickingMethod.SEQUENTIAL_FILLING, false)); } @SneakyThrows @@ -58,17 +57,17 @@ public class TestConfig implements WebMvcConfigurer { for (int i = 1; i <= 5; i++) { var slots = 5 * i; - var room = roomFactory.create(RoomIdentifier.of("test-" + i), instance, slots, json.writeValueAsString(generatePayload()), false); + var room = roomFactory.create(RoomId.of("test-" + i), instance, slots, json.writeValueAsString(generatePayload()), false); roomRepository.create(room); for (int j = 0, n = rand.nextInt(slots + 1); j < n; j++) { - var user = new Entity(EntityIdentifier.of("test-user-" + rand.nextInt(20))); + var user = EntityId.of("test-user-" + rand.nextInt(20)); entityRepository.linkWithRoom(room, List.of(user), false); } } for (int i = 0; i < 5; i++) { - var room = roomFactory.create(RoomIdentifier.of(randomUUID().toString()), instance, IRoom.UNLIMITED_SLOTS, json.writeValueAsString(generatePayload()), false); + var room = roomFactory.create(RoomId.random(), instance, -1, json.writeValueAsString(generatePayload()), false); room.setLocked((i & 1) == 0); roomRepository.create(room); } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java index aeaa773..a965d03 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java @@ -1,52 +1,59 @@ package ru.dragonestia.picker.controller; import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import ru.dragonestia.picker.api.model.account.ResponseAccount; -import ru.dragonestia.picker.api.repository.response.AllAccountsResponse; +import ru.dragonestia.picker.controller.response.ResponseObject; + +import java.util.List; -@Log4j2 @RestController @RequestMapping("/accounts") @RequiredArgsConstructor public class AccountsController { - @GetMapping("/current") - ResponseAccount currentAccount() { + @PreAuthorize("hasRole('ADMIN')") + @GetMapping + List listAccounts() { throw new UnsupportedOperationException("Not implemented"); } @PreAuthorize("hasRole('ADMIN')") - @GetMapping("/{accountId}") - ResponseEntity findAccount(@PathVariable String accountId) { + @GetMapping("/target/{accountId}") + ResponseObject.Account targetAccountDetails(@PathVariable String accountId) { throw new UnsupportedOperationException("Not implemented"); } - @GetMapping - AllAccountsResponse allAccounts() { + @PreAuthorize("hasRole('ADMIN')") + @GetMapping("/list") + ResponseObject.Account listAccountsDetails(@RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } + @PreAuthorize("hasRole('ADMIN')") @PostMapping - ResponseAccount registerAccount(@RequestParam String username, @RequestParam String password, @RequestParam(defaultValue = "") String permissions) { + ResponseEntity createAccount(@RequestParam String username, + @RequestParam String password, + @RequestParam List permissions) { throw new UnsupportedOperationException("Not implemented"); } - @PutMapping("/{accountId}") - ResponseEntity updatePermissions(@PathVariable String accountId, @RequestParam(defaultValue = "") String permissions) { + @PreAuthorize("hasRole('ADMIN')") + @DeleteMapping("/target/{accountId}") + ResponseEntity removeAccount(@PathVariable String accountId) { throw new UnsupportedOperationException("Not implemented"); } - @DeleteMapping("/{accountId}") - ResponseEntity removeAccount(@PathVariable String accountId) { + @PreAuthorize("hasRole('ADMIN')") + @PutMapping("/target/{accountId}/permissions") + ResponseEntity setPermissions(@PathVariable String accountId, + @RequestParam List permissions) { throw new UnsupportedOperationException("Not implemented"); } @PreAuthorize("hasRole('ADMIN') || principal.username.equals(accountId)") - @PutMapping("/{accountId}/password") + @PutMapping("/target/{accountId}/password") ResponseEntity changePassword(@PathVariable String accountId, @RequestParam String newPassword) { throw new UnsupportedOperationException("Not implemented"); } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/EntityController.java b/server/src/main/java/ru/dragonestia/picker/controller/EntityController.java index 69853a4..e9ca650 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/EntityController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/EntityController.java @@ -1,41 +1,28 @@ package ru.dragonestia.picker.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import ru.dragonestia.picker.api.repository.response.LinkedRoomsWithUserResponse; -import ru.dragonestia.picker.api.repository.response.SearchUserResponse; -import ru.dragonestia.picker.api.repository.response.UserDetailsResponse; -@Tag(name = "Users", description = "Entity management") +import java.util.List; +import java.util.Map; + @RequiredArgsConstructor @RestController -@RequestMapping("/users") +@RequestMapping("/entities") public class EntityController { - @Operation(summary = "Search user by identifier") @GetMapping("/search") - SearchUserResponse search( - @Parameter(description = "Entity identifier input") @RequestParam(name = "input") String input - ) { + List search(@RequestParam String input) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Get user info") - @GetMapping("/{userId}") - UserDetailsResponse find( - @Parameter(description = "Entity identifier") @PathVariable(value = "userId") String userId - ) { + @GetMapping("/target/rooms") + List find(@RequestParam String id) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Get rooms linked with user") - @GetMapping("/{userId}/rooms") - LinkedRoomsWithUserResponse roomsOf( - @Parameter(description = "Entity identifier") @PathVariable(value = "userId") String userId - ) { + @GetMapping("/list/rooms") + Map> roomsOf(@RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/EntityRoomController.java b/server/src/main/java/ru/dragonestia/picker/controller/EntityRoomController.java index e843647..e7afb78 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/EntityRoomController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/EntityRoomController.java @@ -1,47 +1,33 @@ package ru.dragonestia.picker.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import ru.dragonestia.picker.api.repository.response.LinkUsersWithRoomResponse; -import ru.dragonestia.picker.api.repository.response.RoomUserListResponse; -@Tag(name = "Users", description = "Entity management") +import java.util.List; + @RequiredArgsConstructor @RestController @RequestMapping("/instances/{instanceId}/rooms/{roomId}/users") public class EntityRoomController { - @Operation(summary = "Get users inside room") @GetMapping - ResponseEntity usersInsideRoom( - @Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId - ) { + List entitiesInsideRoom(@PathVariable String instanceId, @PathVariable String roomId) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Link users with room") @PostMapping - ResponseEntity linkUserWithRoom( - @Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId, - @Parameter(description = "Entity identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds, - @Parameter(description = "Ignore slot limitation") @RequestParam(name = "force") boolean force - ) { + ResponseEntity linkEntitiesWithRoom(@PathVariable String instanceId, + @PathVariable String roomId, + @RequestParam List entities, + @RequestParam(defaultValue = "false") boolean force) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Unlink users from room") @DeleteMapping - ResponseEntity unlinkUsersForBucket( - @Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId, - @Parameter(description = "Entity identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds - ) { + ResponseEntity unlinkEntitiesForBucket(@PathVariable String instanceId, + @PathVariable String roomId, + @RequestParam List entities) { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java b/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java index 950c451..1fe9cf6 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java @@ -1,85 +1,9 @@ package ru.dragonestia.picker.controller; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import ru.dragonestia.picker.api.exception.*; -import ru.dragonestia.picker.api.repository.response.ErrorResponse; - -import java.util.HashMap; @RestControllerAdvice public class ExceptionHandlerController { - @ExceptionHandler(InstanceNotFoundException.class) - ResponseEntity nodeNotFound(InstanceNotFoundException ex) { - return create(404, ex); - } - - @ExceptionHandler(RoomNotFoundException.class) - ResponseEntity roomNotFound(RoomNotFoundException ex) { - return create(404, ex); - } - - @ExceptionHandler(InvalidUsernamesException.class) - ResponseEntity invalidUsernames(InvalidUsernamesException ex) { - return create(400, ex); - } - - @ExceptionHandler(InvalidInstanceIdentifierException.class) - ResponseEntity invalidNodeIdentifier(InvalidInstanceIdentifierException ex) { - return create(400, ex); - } - - @ExceptionHandler(InvalidRoomIdentifierException.class) - ResponseEntity invalidRoomIdentifier(InvalidRoomIdentifierException ex) { - return create(400, ex); - } - - @ExceptionHandler(InstanceAlreadyExistException.class) - ResponseEntity nodeAlreadyExists(InstanceAlreadyExistException ex) { - return create(400, ex); - } - - @ExceptionHandler(RoomAlreadyExistException.class) - ResponseEntity roomAlreadyExists(RoomAlreadyExistException ex) { - return create(400, ex); - } - - @ExceptionHandler(RoomAreFullException.class) - ResponseEntity roomAreFull(RoomAreFullException ex) { - return create(400, ex); - } - - @ExceptionHandler(NoRoomsAvailableException.class) - ResponseEntity noRoomsAvailable(NoRoomsAvailableException ex) { - return create(400, ex); - } - - @ExceptionHandler(NotPersistedNodeException.class) - ResponseEntity notPersistedNode(NotPersistedNodeException ex) { - return create(400, ex); - } - - @ExceptionHandler(AccountDoesNotExistsException.class) - ResponseEntity accountDoesNotExists(AccountDoesNotExistsException ex) { - return create(404, ex); - } - - @ExceptionHandler({PermissionNotFoundException.class}) - ResponseEntity permissionNotFound(PermissionNotFoundException ex) { - return create(400, ex); - } - - @ExceptionHandler({ConstantAdminParamsException.class}) - ResponseEntity constantAdminParams(ConstantAdminParamsException ex) { - return create(401, ex); - } - - private ResponseEntity create(int code, ApiException ex) { - var details = new HashMap(); - ex.appendDetailsToErrorResponse(details); - - return ResponseEntity.status(code).body(new ErrorResponse(ex.getErrorId(), ex.getMessage(), details)); - } + // TODO } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/InstanceController.java b/server/src/main/java/ru/dragonestia/picker/controller/InstanceController.java index e78ea83..4c2109d 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/InstanceController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/InstanceController.java @@ -1,60 +1,52 @@ package ru.dragonestia.picker.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import ru.dragonestia.picker.api.model.node.PickingMethod; -import ru.dragonestia.picker.api.repository.response.NodeDetailsResponse; -import ru.dragonestia.picker.api.repository.response.NodeListResponse; -import ru.dragonestia.picker.api.repository.response.PickedRoomResponse; +import ru.dragonestia.picker.controller.response.ResponseObject; +import ru.dragonestia.picker.model.instance.type.PickingMethod; + +import java.util.List; -@Tag(name = "Nodes", description = "Instance management") @RestController @RequestMapping("/instances") @RequiredArgsConstructor public class InstanceController { - @Operation(summary = "Get all nodes") @GetMapping - NodeListResponse allInstances() { + List listInstances() { + throw new UnsupportedOperationException("Not implemented"); + } + + @GetMapping("/target/{instanceId}") + ResponseObject.Instance targetInstanceDetails(@PathVariable String instanceId) { + throw new UnsupportedOperationException("Not implemented"); + } + + @GetMapping("/list") + List listInstancesDetails(@RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Register new node") @PostMapping - ResponseEntity registerInstance( - @Parameter(description = "Instance identifier") @RequestParam(name = "instanceId") String instanceId, - @Parameter(description = "Picking method method") @RequestParam(name = "method") PickingMethod method, - @Parameter(description = "Save node") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist - ) { + ResponseEntity createInstance(@RequestParam String instanceId, + @RequestParam PickingMethod method, + @RequestParam(defaultValue = "false") boolean persist) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Get node details") - @GetMapping("/{instanceId}") - ResponseEntity instanceDetails( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId - ) { + @DeleteMapping("/target/{instanceId}") + ResponseEntity deleteInstance(@PathVariable String instanceId) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Unregister node") - @DeleteMapping("/{instanceId}") - ResponseEntity removeInstance( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId - ) { + @DeleteMapping("/list") + ResponseEntity deleteInstances(@RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Pick node for users") - @PostMapping("/{instanceId}/pick") - ResponseEntity pickRoom( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId, - @RequestBody String userIds - ) { + @PostMapping("/target/{instanceId}/pick") + ResponseObject.PickedRoom pickRoom(@PathVariable String instanceId, @RequestBody List entities) { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java b/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java index e0e61f5..a67226d 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java @@ -1,68 +1,54 @@ package ru.dragonestia.picker.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import ru.dragonestia.picker.api.repository.response.RoomInfoResponse; -import ru.dragonestia.picker.api.repository.response.RoomListResponse; +import ru.dragonestia.picker.controller.response.ResponseObject; + +import java.util.List; -@Tag(name = "Rooms", description = "Room management") @RestController -@RequestMapping("/instances/{instanceId}/rooms") +@RequestMapping("/instances/target/{instanceId}/rooms") @RequiredArgsConstructor public class RoomController { - @Operation(summary = "Get all rooms from node") @GetMapping - ResponseEntity all( - @Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId - ) { + List listRooms(@PathVariable String instanceId) { + throw new UnsupportedOperationException("Not implemented"); + } + + @GetMapping("/target/{roomId}") + ResponseObject.Room targetRoomDetails(@PathVariable String instanceId, @PathVariable String roomId) { + throw new UnsupportedOperationException("Not implemented"); + } + + @GetMapping("/list") + List listRoomDetails(@PathVariable String instanceId, @RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Register new room") @PostMapping - ResponseEntity register( - @Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId, - @Parameter(description = "Room identifier") @RequestParam(name = "roomId") String roomId, - @Parameter(description = "Maximum users count in room") @RequestParam(name = "slots") int slots, - @Parameter(description = "Payload. Some data") @RequestParam(name = "payload") String payload, - @Parameter(description = "Lock for picking") @RequestParam(name = "locked", required = false, defaultValue = "false") boolean locked, - @Parameter(description = "Save room") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist - ) { + ResponseEntity createRoom(@PathVariable String instanceId, + @RequestParam String id, + @RequestParam int slots, + @RequestParam String payload, + @RequestParam(defaultValue = "false") boolean locked, + @RequestParam(defaultValue = "false") boolean persist) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Unregister room") - @DeleteMapping("/{roomId}") - ResponseEntity remove( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable("roomId") String roomId - ) { + @DeleteMapping("/target/{roomId}") + ResponseEntity deleteRoom(@PathVariable String instanceId, @PathVariable String roomId) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Get room details") - @GetMapping("/{roomId}") - ResponseEntity info( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable("roomId") String roomId - ) { + @DeleteMapping("/list") + ResponseEntity deleteRooms(@PathVariable String instanceId, @RequestParam List id) { throw new UnsupportedOperationException("Not implemented"); } - @Operation(summary = "Lock/unlock room") - @ApiResponse(description = "New lock state") - @PutMapping("/{roomId}/lock") - ResponseEntity lockRoom( - @Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId, - @Parameter(description = "Room identifier") @PathVariable("roomId") String roomId, - @Parameter(description = "New state for Lock property") @RequestParam(name = "newState") boolean value - ) { + @PutMapping("/target/{roomId}/lock") + ResponseEntity lockRoom(@PathVariable String instanceId, @PathVariable String roomId, @RequestParam boolean newState) { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/RoomPickerController.java b/server/src/main/java/ru/dragonestia/picker/controller/RoomPickerController.java index 496f4d3..eb770d1 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/RoomPickerController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/RoomPickerController.java @@ -1,16 +1,12 @@ package ru.dragonestia.picker.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import ru.dragonestia.picker.api.repository.response.RoomPickerInfoResponse; +import ru.dragonestia.picker.controller.response.RoomPickerInfoResponse; -@Tag(name = "RoomPicker") @RestController public class RoomPickerController { - @Operation(summary = "Server info") @GetMapping("/info") RoomPickerInfoResponse info() { return new RoomPickerInfoResponse("v0.0.1"); diff --git a/server/src/main/java/ru/dragonestia/picker/controller/graphql/GraphqlController.java b/server/src/main/java/ru/dragonestia/picker/controller/graphql/GraphqlController.java index 1ba41c2..c584072 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/graphql/GraphqlController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/graphql/GraphqlController.java @@ -4,12 +4,14 @@ import jakarta.validation.constraints.NotNull; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.stereotype.Controller; -import ru.dragonestia.picker.api.repository.type.EntityIdentifier; import ru.dragonestia.picker.controller.graphql.object.ObjectInstance; import ru.dragonestia.picker.controller.graphql.object.ObjectRoom; import ru.dragonestia.picker.controller.graphql.object.ObjectEntity; import ru.dragonestia.picker.controller.graphql.object.type.DataProvider; import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.room.RoomId; import ru.dragonestia.picker.service.InstanceService; import ru.dragonestia.picker.service.RoomService; import ru.dragonestia.picker.service.EntityService; @@ -40,40 +42,40 @@ public class GraphqlController { @QueryMapping ObjectInstance instanceById(@Argument String id) { - return instanceService.find(id) + return instanceService.find(InstanceId.of(id)) .map(node -> new ObjectInstance(node, dataProvider)) .orElse(null); } @QueryMapping List allRooms(@NotNull String nodeId) { - var node = instanceService.find(nodeId).orElse(null); + var node = instanceService.find(InstanceId.of(nodeId)).orElse(null); if (node == null) return null; - return roomService.all(node).stream() + return roomService.all(node.getId()).stream() .map(room -> new ObjectRoom(room, dataProvider)) .toList(); } @QueryMapping ObjectRoom roomById(@Argument String nodeId, @NotNull String roomId) { - var node = instanceService.find(nodeId).orElse(null); + var node = instanceService.find(InstanceId.of(nodeId)).orElse(null); if (node == null) return null; - return roomService.find(node, roomId) + return roomService.find(node.getId(), RoomId.of(roomId)) .map(room -> new ObjectRoom(room, dataProvider)) .orElse(null); } @QueryMapping ObjectEntity entityById(@Argument String id) { - return new ObjectEntity(new Entity(EntityIdentifier.of(id)), dataProvider); + return new ObjectEntity(new Entity(EntityId.of(id)), dataProvider); } @QueryMapping List searchEntity(@Argument String input) { - return entityService.searchEntities(input).stream() - .map(user -> new ObjectEntity(new Entity(user.getIdentifierObject()), dataProvider)) + return entityService.searchEntities(EntityId.of(input)).stream() + .map(user -> new ObjectEntity(new Entity(user.getId()), dataProvider)) .toList(); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectEntity.java b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectEntity.java index f133603..e3b78e4 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectEntity.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectEntity.java @@ -15,7 +15,7 @@ public class ObjectEntity { private List cachedRooms = null; public @NotNull String getId() { - return entity.getIdentifier(); + return entity.getId().getValue(); } public List getRooms() { @@ -23,7 +23,7 @@ public class ObjectEntity { return cachedRooms; } - cachedRooms = dataProvider.entityService().getEntityRooms(entity).stream() + cachedRooms = dataProvider.entityService().getEntityRooms(entity.getId()).stream() .map(room -> new ObjectRoom(room, dataProvider)) .toList(); diff --git a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectInstance.java b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectInstance.java index 05aae6e..8093360 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectInstance.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectInstance.java @@ -14,7 +14,7 @@ public class ObjectInstance { private List cachedRooms = null; public String getId() { - return instance.getIdentifier(); + return instance.getId().getValue(); } public String getMethod() { @@ -26,7 +26,7 @@ public class ObjectInstance { return cachedRooms; } - cachedRooms = dataProvider.roomService().all(instance).stream() + cachedRooms = dataProvider.roomService().all(instance.getId()).stream() .map(room -> new ObjectRoom(room, dataProvider)) .toList(); diff --git a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectRoom.java b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectRoom.java index db06bd2..0e1528a 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectRoom.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/graphql/object/ObjectRoom.java @@ -14,21 +14,21 @@ public class ObjectRoom { private List cachedUsers = null; public String getId() { - return room.getIdentifier(); + return room.getId().getValue(); } public String getInstanceId() { - return room.getInstanceIdentifier(); + return room.getInstance().getId().getValue(); } public ObjectInstance getInstance() { - return dataProvider.instanceService().find(room.getInstanceIdentifier()) + return dataProvider.instanceService().find(room.getInstance().getId()) .map(node -> new ObjectInstance(node, dataProvider)) .orElseThrow(); } public int getSlots() { - return room.getMaxSlots(); + return room.getSlots(); } public String getPayload() { diff --git a/server/src/main/java/ru/dragonestia/picker/controller/response/ResponseObject.java b/server/src/main/java/ru/dragonestia/picker/controller/response/ResponseObject.java new file mode 100644 index 0000000..0ca87fb --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/controller/response/ResponseObject.java @@ -0,0 +1,19 @@ +package ru.dragonestia.picker.controller.response; + +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.type.PickingMethod; + +import java.util.List; + +public final class ResponseObject { + + private ResponseObject() {} + + public record Instance(String id, PickingMethod method, boolean persist) {} + + public record Room(String id, String nodeId, int slots, boolean locked, boolean persist, String payload) {} + + public record PickedRoom(Room room, List entities) {} + + public record Account(String id, List permissions, boolean locked) {} +} diff --git a/server/src/main/java/ru/dragonestia/picker/controller/response/RoomPickerInfoResponse.java b/server/src/main/java/ru/dragonestia/picker/controller/response/RoomPickerInfoResponse.java new file mode 100644 index 0000000..5b09200 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/controller/response/RoomPickerInfoResponse.java @@ -0,0 +1,3 @@ +package ru.dragonestia.picker.controller.response; + +public record RoomPickerInfoResponse(String version) {} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/AdminAccountMutationException.java b/server/src/main/java/ru/dragonestia/picker/exception/AdminAccountMutationException.java new file mode 100644 index 0000000..4cfff65 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/AdminAccountMutationException.java @@ -0,0 +1,8 @@ +package ru.dragonestia.picker.exception; + +public class AdminAccountMutationException extends RuntimeException { + + public AdminAccountMutationException() { + super("Cannot mutate admin account"); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/AlreadyExistsException.java b/server/src/main/java/ru/dragonestia/picker/exception/AlreadyExistsException.java new file mode 100644 index 0000000..ac7e4e0 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/AlreadyExistsException.java @@ -0,0 +1,19 @@ +package ru.dragonestia.picker.exception; + +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.room.RoomId; + +public class AlreadyExistsException extends RuntimeException { + + public AlreadyExistsException(String message) { + super(message); + } + + public static AlreadyExistsException forInstance(InstanceId instanceId) { + return new AlreadyExistsException("Instance with id '%s' already created".formatted(instanceId.getValue())); + } + + public static AlreadyExistsException forRoom(InstanceId instanceId, RoomId roomId) { + return new AlreadyExistsException("Room with id '%s' already exists in instance '%s".formatted(roomId.getValue(), instanceId.getValue())); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/ConflictingPersistParametersException.java b/server/src/main/java/ru/dragonestia/picker/exception/ConflictingPersistParametersException.java new file mode 100644 index 0000000..b38b0dd --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/ConflictingPersistParametersException.java @@ -0,0 +1,19 @@ +package ru.dragonestia.picker.exception; + +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.room.RoomId; + +public class ConflictingPersistParametersException extends RuntimeException { + + public ConflictingPersistParametersException(String message) { + super(message); + } + + public static ConflictingPersistParametersException forRoom(InstanceId instanceId, RoomId roomId) { + return new ConflictingPersistParametersException("Tried create persisted room '%s' for not persisted instance '%s'" + .formatted( + roomId.getValue(), + instanceId.getValue() + )); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/DoesNotExistsException.java b/server/src/main/java/ru/dragonestia/picker/exception/DoesNotExistsException.java new file mode 100644 index 0000000..6f690e9 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/DoesNotExistsException.java @@ -0,0 +1,19 @@ +package ru.dragonestia.picker.exception; + +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.room.RoomId; + +public class DoesNotExistsException extends RuntimeException { + + public DoesNotExistsException(String message) { + super(message); + } + + public static DoesNotExistsException forInstance(InstanceId id) { + return new DoesNotExistsException("Does not exists instance with id '%s'".formatted(id.toString())); + } + + public static DoesNotExistsException forRoom(RoomId id) { + return new DoesNotExistsException("Does not exists room with id '%s'".formatted(id.toString())); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/InvalidIdentifierException.java b/server/src/main/java/ru/dragonestia/picker/exception/InvalidIdentifierException.java new file mode 100644 index 0000000..38d9293 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/InvalidIdentifierException.java @@ -0,0 +1,14 @@ +package ru.dragonestia.picker.exception; + +import org.jetbrains.annotations.Nullable; + +public class InvalidIdentifierException extends RuntimeException { + + public InvalidIdentifierException(String message) { + super(message); + } + + public static InvalidIdentifierException taken(@Nullable String input) { + return new InvalidIdentifierException("Taken identifier: " + input); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/NoRoomsAvailableException.java b/server/src/main/java/ru/dragonestia/picker/exception/NoRoomsAvailableException.java new file mode 100644 index 0000000..62703b8 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/NoRoomsAvailableException.java @@ -0,0 +1,10 @@ +package ru.dragonestia.picker.exception; + +import ru.dragonestia.picker.model.instance.InstanceId; + +public class NoRoomsAvailableException extends RuntimeException { + + public NoRoomsAvailableException(InstanceId instanceId) { + super("There are no rooms available in instance '" + instanceId.getValue() + "'"); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/exception/RoomAreFullException.java b/server/src/main/java/ru/dragonestia/picker/exception/RoomAreFullException.java new file mode 100644 index 0000000..8eecadf --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/exception/RoomAreFullException.java @@ -0,0 +1,11 @@ +package ru.dragonestia.picker.exception; + +import ru.dragonestia.picker.model.instance.InstanceId; +import ru.dragonestia.picker.model.room.RoomId; + +public class RoomAreFullException extends RuntimeException { + + public RoomAreFullException(InstanceId instanceId, RoomId roomId) { + super("Room '%s' in instance '%s' are full".formatted(roomId.getValue(), instanceId.toString())); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/account/Account.java b/server/src/main/java/ru/dragonestia/picker/model/account/Account.java index 4bd8b6d..55ffeb8 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/account/Account.java +++ b/server/src/main/java/ru/dragonestia/picker/model/account/Account.java @@ -1,66 +1,37 @@ package ru.dragonestia.picker.model.account; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; +import lombok.Getter; +import lombok.Setter; import org.springframework.security.core.userdetails.UserDetails; -import ru.dragonestia.picker.api.model.account.IAccount; -import ru.dragonestia.picker.api.model.account.ResponseAccount; import java.util.Collection; import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; -public class Account implements IAccount, UserDetails { +public class Account implements UserDetails { - private final String username; + @Getter private final AccountId id; + @Getter private final String username; private final String lowerUsername; - private String password; + @Getter @Setter private String password; private Set permissions = new HashSet<>(); - private boolean locked = false; - private boolean enabled = true; + @Getter @Setter private boolean locked = false; + @Getter @Setter private boolean enabled = true; - public Account(@NotNull String username, @NotNull String password) { - this.username = username; + public Account(AccountId id, String password) { + this.id = id; + this.username = id.getValue(); this.lowerUsername = username.toLowerCase(); this.password = password; } @Override - public @NotNull Collection getAuthorities() { + public Collection getAuthorities() { return permissions; } - @Override - public boolean isLocked() { - return locked; - } - - @Contract("_ -> this") - public @NotNull Account setAuthorities(@NotNull Set permissions) { + public void setAuthorities(Set permissions) { this.permissions = permissions; - return this; - } - - @Override - public @NotNull String getPassword() { - return password; - } - - @Override - public @NotNull Set getPermissions() { - return getAuthorities().stream().map(Enum::name).collect(Collectors.toSet()); - } - - @Contract("_ -> this") - public @NotNull Account setPassword(String value) { - password = value; - return this; - } - - @Override - public @NotNull String getUsername() { - return username; } @Override @@ -73,28 +44,11 @@ public class Account implements IAccount, UserDetails { return !locked; } - @Contract("_ -> this") - public @NotNull Account setLocked(boolean value) { - locked = value; - return this; - } - @Override public boolean isCredentialsNonExpired() { return true; } - @Override - public boolean isEnabled() { - return enabled; - } - - @Contract("_ -> this") - public @NotNull Account setEnabled(boolean value) { - enabled = value; - return this; - } - @Override public int hashCode() { return lowerUsername.hashCode(); @@ -109,8 +63,4 @@ public class Account implements IAccount, UserDetails { } return false; } - - public @NotNull ResponseAccount toResponseObject() { - return new ResponseAccount(username, password, getPermissions(), locked); - } } diff --git a/server/src/main/java/ru/dragonestia/picker/model/account/AccountId.java b/server/src/main/java/ru/dragonestia/picker/model/account/AccountId.java new file mode 100644 index 0000000..73eeee0 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/account/AccountId.java @@ -0,0 +1,42 @@ +package ru.dragonestia.picker.model.account; + +import lombok.Getter; +import ru.dragonestia.picker.exception.InvalidIdentifierException; + +import java.util.Objects; + +@Getter +public final class AccountId { + + private final String value; + + private AccountId(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AccountId accountId = (AccountId) o; + return Objects.equals(value, accountId.value); + } + + public static AccountId of(String identifier) throws InvalidIdentifierException { + if (identifier.matches("^[aA-zZ\\d]{3,32}$")) { + return new AccountId(identifier); + } + + throw InvalidIdentifierException.taken(identifier); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/entity/Entity.java b/server/src/main/java/ru/dragonestia/picker/model/entity/Entity.java index 19339b7..d8fba9f 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/entity/Entity.java +++ b/server/src/main/java/ru/dragonestia/picker/model/entity/Entity.java @@ -1,42 +1,24 @@ package ru.dragonestia.picker.model.entity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import ru.dragonestia.picker.api.model.user.IUser; -import ru.dragonestia.picker.api.model.user.ResponseUser; -import ru.dragonestia.picker.api.model.user.UserDetails; -import ru.dragonestia.picker.api.repository.type.EntityIdentifier; +import lombok.Getter; -public class Entity implements IUser { +@Getter +public class Entity { - private final String identifier; + private final EntityId id; - public Entity(@NotNull EntityIdentifier identifier) { - this.identifier = identifier.getValue(); - } - - @Override - public @NotNull String getIdentifier() { - return identifier; - } - - @Override - public @Nullable String getDetail(@NotNull UserDetails detail) { - throw new UnsupportedOperationException(); - } - - public @NotNull ResponseUser toResponseObject() { - return new ResponseUser(identifier); + public Entity(EntityId id) { + this.id = id; } @Override public String toString() { - return identifier; + return id.getValue(); } @Override public int hashCode() { - return identifier.hashCode(); + return id.hashCode(); } @Override @@ -44,7 +26,7 @@ public class Entity implements IUser { if (object == this) return true; if (object == null) return false; if (object instanceof Entity other) { - return identifier.equals(other.identifier); + return id.equals(other.id); } return false; } diff --git a/server/src/main/java/ru/dragonestia/picker/model/entity/EntityId.java b/server/src/main/java/ru/dragonestia/picker/model/entity/EntityId.java new file mode 100644 index 0000000..2f6537f --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/entity/EntityId.java @@ -0,0 +1,42 @@ +package ru.dragonestia.picker.model.entity; + +import lombok.Getter; +import ru.dragonestia.picker.exception.InvalidIdentifierException; + +import java.util.Objects; + +@Getter +public final class EntityId { + + private final String value; + + private EntityId(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EntityId entityId = (EntityId) o; + return Objects.equals(value, entityId.value); + } + + public static EntityId of(String identifier) throws InvalidIdentifierException { + if (identifier.matches("^[aA-zZ\\d-.\\s:@_;]{1,64}$")) { + return new EntityId(identifier); + } + + throw InvalidIdentifierException.taken(identifier); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/factory/RoomFactory.java b/server/src/main/java/ru/dragonestia/picker/model/factory/RoomFactory.java deleted file mode 100644 index 4dbe7ca..0000000 --- a/server/src/main/java/ru/dragonestia/picker/model/factory/RoomFactory.java +++ /dev/null @@ -1,19 +0,0 @@ -package ru.dragonestia.picker.model.factory; - -import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.springframework.stereotype.Component; -import ru.dragonestia.picker.api.repository.type.RoomIdentifier; -import ru.dragonestia.picker.model.instance.Instance; -import ru.dragonestia.picker.model.room.Room; - -@Component -@RequiredArgsConstructor -public class RoomFactory { - - @Contract("_, _, _, _, _ -> new") - public @NotNull Room create(@NotNull RoomIdentifier identifier, @NotNull Instance instance, int slots, @NotNull String payload, boolean persist) { - return new Room(identifier, instance, slots, payload, persist); - } -} diff --git a/server/src/main/java/ru/dragonestia/picker/model/instance/Instance.java b/server/src/main/java/ru/dragonestia/picker/model/instance/Instance.java index 07f0d88..23fcbf0 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/instance/Instance.java +++ b/server/src/main/java/ru/dragonestia/picker/model/instance/Instance.java @@ -1,52 +1,24 @@ package ru.dragonestia.picker.model.instance; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import ru.dragonestia.picker.api.model.node.INode; -import ru.dragonestia.picker.api.model.node.NodeDetails; -import ru.dragonestia.picker.api.model.node.PickingMethod; -import ru.dragonestia.picker.api.model.node.ResponseNode; -import ru.dragonestia.picker.api.repository.type.NodeIdentifier; +import lombok.Getter; +import ru.dragonestia.picker.model.instance.type.PickingMethod; -public class Instance implements INode { +@Getter +public class Instance { - private final String identifier; + private final InstanceId id; private final PickingMethod pickingMethod; private final boolean persist; - public Instance(@NotNull NodeIdentifier identifier, @NotNull PickingMethod pickingMethod, boolean persist) { - this.identifier = identifier.getValue(); + public Instance(InstanceId id, PickingMethod pickingMethod, boolean persist) { + this.id = id; this.pickingMethod = pickingMethod; this.persist = persist; } - @Override - public @NotNull String getIdentifier() { - return identifier; - } - - @Override - public @NotNull PickingMethod getPickingMethod() { - return pickingMethod; - } - - @Override - public @NotNull Boolean isPersist() { - return persist; - } - - @Override - public @Nullable String getDetail(@NotNull NodeDetails detail) { - throw new UnsupportedOperationException(); - } - - public @NotNull ResponseNode toResponseObject() { - return new ResponseNode(identifier, pickingMethod); - } - @Override public int hashCode() { - return identifier.hashCode(); + return id.hashCode(); } @Override @@ -54,13 +26,13 @@ public class Instance implements INode { if (object == this) return true; if (object == null) return false; if (object instanceof Instance other) { - return identifier.equals(other.identifier); + return id.equals(other.id); } return false; } @Override public String toString() { - return "{Instance id='%s'}".formatted(identifier); + return "{Instance id='%s'}".formatted(id); } } diff --git a/server/src/main/java/ru/dragonestia/picker/model/instance/InstanceId.java b/server/src/main/java/ru/dragonestia/picker/model/instance/InstanceId.java new file mode 100644 index 0000000..41950ee --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/instance/InstanceId.java @@ -0,0 +1,53 @@ +package ru.dragonestia.picker.model.instance; + +import lombok.Getter; +import ru.dragonestia.picker.exception.InvalidIdentifierException; + +import java.util.Objects; +import java.util.Random; + +@Getter +public final class InstanceId { + + private static final Random random = new Random(); + + private final String value; + + private InstanceId(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InstanceId that = (InstanceId) o; + return Objects.equals(value, that.value); + } + + public static InstanceId of(String identifier) throws InvalidIdentifierException { + if (identifier.matches("^(?!-)[a-z\\d-]{0,31}[a-z\\d](?!-)$")) { + return new InstanceId(identifier); + } + + throw InvalidIdentifierException.taken(identifier); + } + + public static InstanceId random() { + char[] chars = new char[32]; + for (int i = 0; i < chars.length; i++) { + chars[i] = (char) ('a' + random.nextInt('z' - 'a')); + } + return new InstanceId(new String(chars)); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/instance/type/PickingMethod.java b/server/src/main/java/ru/dragonestia/picker/model/instance/type/PickingMethod.java new file mode 100644 index 0000000..952d066 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/instance/type/PickingMethod.java @@ -0,0 +1,7 @@ +package ru.dragonestia.picker.model.instance.type; + +public enum PickingMethod { + SEQUENTIAL_FILLING, + ROUND_ROBIN, + LEAST_PICKED +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/room/Room.java b/server/src/main/java/ru/dragonestia/picker/model/room/Room.java index 241cd55..9c4fcce 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/room/Room.java +++ b/server/src/main/java/ru/dragonestia/picker/model/room/Room.java @@ -1,89 +1,32 @@ package ru.dragonestia.picker.model.room; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import ru.dragonestia.picker.api.model.room.IRoom; -import ru.dragonestia.picker.api.model.room.ResponseRoom; -import ru.dragonestia.picker.api.model.room.RoomDetails; -import ru.dragonestia.picker.api.model.room.ShortResponseRoom; -import ru.dragonestia.picker.api.repository.type.RoomIdentifier; +import lombok.Getter; +import lombok.Setter; import ru.dragonestia.picker.model.instance.Instance; import java.util.Objects; -public class Room implements IRoom { +@Getter +public class Room { - private final String identifier; - private final String instanceIdentifier; + private final RoomId id; + private final Instance instance; private final int slots; private final String payload; private final boolean persist; - private boolean locked = false; + @Setter private boolean locked = false; - public Room(@NotNull RoomIdentifier identifier, @NotNull Instance instance, int slots, @NotNull String payload, boolean persist) { - this.identifier = identifier.getValue(); - this.instanceIdentifier = instance.getIdentifier(); + public Room(RoomId id, Instance instance, int slots, String payload, boolean persist) { + this.id = id; + this.instance = instance; this.slots = slots; this.payload = payload; this.persist = persist; } - @Override - public @NotNull String getIdentifier() { - return identifier; - } - - @Override - public @NotNull String getInstanceIdentifier() { - return instanceIdentifier; - } - - @Override - public int getMaxSlots() { - return slots; - } - - @Override - public boolean isLocked() { - return locked; - } - - public void setLocked(boolean value) { - locked = value; - } - - @Override - public @NotNull Boolean isPersist() { - return persist; - } - - @Override - public @NotNull String getPayload() { - return payload; - } - - @Override - public @Nullable String getDetail(@NotNull RoomDetails detail) { - throw new UnsupportedOperationException(); - } - - public boolean isAvailable(int usedSlots, int requiredSlots) { - if (locked) return false; - if (hasUnlimitedSlots()) return true; - return slots >= usedSlots + requiredSlots; - } - - public @NotNull ResponseRoom toResponseObject() { - return new ResponseRoom(identifier, instanceIdentifier, slots, locked, payload); - } - - public @NotNull ShortResponseRoom toShortResponseObject() { - return new ShortResponseRoom(identifier, instanceIdentifier, slots, locked); - } - @Override public int hashCode() { - return Objects.hash(identifier, instanceIdentifier); + return Objects.hash(id, instance.getId()); } @Override @@ -91,7 +34,7 @@ public class Room implements IRoom { if (object == this) return true; if (object == null) return false; if (object instanceof Room other) { - return identifier.equals(other.identifier) && instanceIdentifier.equals(other.instanceIdentifier); + return id.equals(other.id) && instance.getId().equals(other.instance.getId()); } return false; } diff --git a/server/src/main/java/ru/dragonestia/picker/model/room/RoomId.java b/server/src/main/java/ru/dragonestia/picker/model/room/RoomId.java new file mode 100644 index 0000000..1fc6751 --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/room/RoomId.java @@ -0,0 +1,54 @@ +package ru.dragonestia.picker.model.room; + +import lombok.Getter; +import ru.dragonestia.picker.exception.InvalidIdentifierException; +import ru.dragonestia.picker.model.instance.InstanceId; + +import java.util.Objects; +import java.util.Random; + +@Getter +public final class RoomId { + + private final static Random random = new Random(); + + private final String value; + + private RoomId(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RoomId roomId = (RoomId) o; + return Objects.equals(value, roomId.value); + } + + public static RoomId of(String identifier) throws InvalidIdentifierException { + if (identifier.matches("^(?!-)[a-z\\d-]{0,31}[a-z\\d](?!-)$")) { + return new RoomId(identifier); + } + + throw InvalidIdentifierException.taken(identifier); + } + + public static RoomId random() { + char[] chars = new char[32]; + for (int i = 0; i < chars.length; i++) { + chars[i] = (char) ('a' + random.nextInt('z' - 'a')); + } + return new RoomId(new String(chars)); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/model/room/factory/RoomFactory.java b/server/src/main/java/ru/dragonestia/picker/model/room/factory/RoomFactory.java new file mode 100644 index 0000000..1a0f88e --- /dev/null +++ b/server/src/main/java/ru/dragonestia/picker/model/room/factory/RoomFactory.java @@ -0,0 +1,16 @@ +package ru.dragonestia.picker.model.room.factory; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.room.Room; +import ru.dragonestia.picker.model.room.RoomId; + +@Component +@RequiredArgsConstructor +public class RoomFactory { + + public Room create(RoomId identifier, Instance instance, int slots, String payload, boolean persist) { + return new Room(identifier, instance, slots, payload, persist); + } +} diff --git a/server/src/main/java/ru/dragonestia/picker/repository/EntityRepository.java b/server/src/main/java/ru/dragonestia/picker/repository/EntityRepository.java index 4fa7fa1..1b1923b 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/EntityRepository.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/EntityRepository.java @@ -1,6 +1,7 @@ package ru.dragonestia.picker.repository; -import ru.dragonestia.picker.api.exception.RoomAreFullException; +import ru.dragonestia.picker.exception.RoomAreFullException; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; @@ -9,17 +10,17 @@ import java.util.Map; public interface EntityRepository { - void linkWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException; + void linkWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException; - void unlinkWithRoom(Room room, Collection entities); + void unlinkWithRoom(Room room, Collection entities); - Collection findAllLinkedEntityRooms(Entity entity); + Collection findAllLinkedEntityRooms(EntityId entity); Collection entitiesOf(Room room); - Collection search(String input); + Collection search(EntityId input); int countAllEntities(); - Map countEntitiesForNodes(); + Map countEntitiesForInstances(); } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/InstanceRepository.java b/server/src/main/java/ru/dragonestia/picker/repository/InstanceRepository.java index 40ad32d..2c42a61 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/InstanceRepository.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/InstanceRepository.java @@ -1,18 +1,19 @@ package ru.dragonestia.picker.repository; -import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.instance.InstanceId; import java.util.List; import java.util.Optional; public interface InstanceRepository { - void create(Instance instance) throws InstanceAlreadyExistException; + void create(Instance instance) throws AlreadyExistsException; - void delete(Instance instance); + void delete(InstanceId id); - Optional findById(String nodeId); + Optional findById(InstanceId id); List all(); } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/RoomRepository.java b/server/src/main/java/ru/dragonestia/picker/repository/RoomRepository.java index 8144840..a7343b5 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/RoomRepository.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/RoomRepository.java @@ -1,10 +1,11 @@ package ru.dragonestia.picker.repository; -import ru.dragonestia.picker.api.exception.NoRoomsAvailableException; -import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; -import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.NoRoomsAvailableException; +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.model.room.Room; -import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.room.RoomId; import java.util.Collection; import java.util.Optional; @@ -12,13 +13,13 @@ import java.util.Set; public interface RoomRepository { - void create(Room room) throws RoomAlreadyExistException; + void create(Room room) throws AlreadyExistsException; - void remove(Room room); + void remove(InstanceId instanceId, RoomId roomId); - Optional find(Instance instance, String identifier); + Optional find(InstanceId instanceId, RoomId roomId); - Collection all(Instance instance); + Collection all(InstanceId instanceId); - Room pick(Instance instance, Set entities) throws NoRoomsAvailableException; + Room pick(InstanceId instanceId, Set entities) throws NoRoomsAvailableException; } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/ContainerRepository.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/ContainerRepository.java index d12392c..4cd70fe 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/ContainerRepository.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/ContainerRepository.java @@ -2,8 +2,9 @@ package ru.dragonestia.picker.repository.impl; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; -import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.repository.impl.container.InstanceContainer; import ru.dragonestia.picker.repository.impl.type.EntityTransaction; @@ -15,25 +16,25 @@ import java.util.concurrent.ConcurrentHashMap; @Component public class ContainerRepository { - private final Map containers = new ConcurrentHashMap<>(); + private final Map containers = new ConcurrentHashMap<>(); private EntityTransaction.Listener transactionListener = transaction -> {}; - public void create(Instance instance) throws InstanceAlreadyExistException { - if (containers.containsKey(instance.getIdentifier())) { - throw new InstanceAlreadyExistException(instance.getIdentifier()); + public void create(Instance instance) throws AlreadyExistsException { + if (containers.containsKey(instance.getId())) { + throw AlreadyExistsException.forInstance(instance.getId()); } var container = new InstanceContainer(instance, transactionListener); - containers.put(instance.getIdentifier(), container); + containers.put(instance.getId(), container); } - public void remove(@NotNull String instanceId) { - containers.remove(instanceId); + public void remove(InstanceId id) { + containers.remove(id); } - public @NotNull Optional findById(@NotNull String instanceId) { - return Optional.ofNullable(containers.get(instanceId)); + public @NotNull Optional findById(InstanceId id) { + return Optional.ofNullable(containers.get(id)); } public @NotNull Collection all() { diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/EntityRepositoryImpl.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/EntityRepositoryImpl.java index 4e2b2fd..4590140 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/EntityRepositoryImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/EntityRepositoryImpl.java @@ -3,9 +3,9 @@ package ru.dragonestia.picker.repository.impl; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import ru.dragonestia.picker.api.exception.InstanceNotFoundException; -import ru.dragonestia.picker.api.exception.RoomAreFullException; -import ru.dragonestia.picker.api.exception.RoomNotFoundException; +import ru.dragonestia.picker.exception.DoesNotExistsException; +import ru.dragonestia.picker.exception.RoomAreFullException; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; import ru.dragonestia.picker.repository.EntityRepository; @@ -20,14 +20,14 @@ public class EntityRepositoryImpl implements EntityRepository { private final ContainerRepository containerRepository; - private final Map> entityRooms = new ConcurrentHashMap<>(); + private final Map> entityRooms = new ConcurrentHashMap<>(); @PostConstruct void init() { containerRepository.setTransactionListener(transaction -> { synchronized (entityRooms) { for (var entity: transaction.target()) { - var set = entityRooms.computeIfAbsent(entity, k -> new HashSet<>()); + var set = entityRooms.computeIfAbsent(entity.getId(), k -> new HashSet<>()); set.add(transaction.room()); } } @@ -35,9 +35,9 @@ public class EntityRepositoryImpl implements EntityRepository { } @Override - public void linkWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException { + public void linkWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException { synchronized (entityRooms) { - getRoomContainer(room).addEntities(entities, force); + getRoomContainer(room).addEntities(entities.stream().map(Entity::new).toList(), force); for (var entity: entities) { var set = entityRooms.computeIfAbsent(entity, k -> new HashSet<>()); @@ -47,9 +47,9 @@ public class EntityRepositoryImpl implements EntityRepository { } @Override - public void unlinkWithRoom(Room room, Collection entities) { + public void unlinkWithRoom(Room room, Collection entities) { synchronized (entityRooms) { - getRoomContainer(room).removeEntities(entities); + getRoomContainer(room).removeEntities(entities.stream().map(Entity::new).toList()); for (var entity: entities) { var set = entityRooms.get(entity); @@ -61,7 +61,7 @@ public class EntityRepositoryImpl implements EntityRepository { } @Override - public Collection findAllLinkedEntityRooms(Entity entity) { + public Collection findAllLinkedEntityRooms(EntityId entity) { var result = entityRooms.get(entity); return Collections.unmodifiableSet(result == null? new HashSet<>() : result); } @@ -72,8 +72,12 @@ public class EntityRepositoryImpl implements EntityRepository { } @Override - public Collection search(String input) { - return entityRooms.keySet().stream().filter(entity -> entity.getIdentifier().startsWith(input)).toList(); + public Collection search(EntityId input) { + var inputStr = input.getValue(); + return entityRooms.keySet().stream() + .filter(entity -> entity.getValue().startsWith(inputStr)) + .map(Entity::new) + .toList(); } @Override @@ -82,14 +86,14 @@ public class EntityRepositoryImpl implements EntityRepository { } @Override - public Map countEntitiesForNodes() { + public Map countEntitiesForInstances() { var result = new HashMap(); containerRepository.all().forEach(nodeContainer -> { - var nodeId = nodeContainer.getInstance().getIdentifier(); + var nodeId = nodeContainer.getInstance().getId(); nodeContainer.allRooms().forEach(roomContainer -> { - result.put(nodeId, result.getOrDefault(nodeId, 0) + roomContainer.countEntities()); + result.put(nodeId.getValue(), result.getOrDefault(nodeId.getValue(), 0) + roomContainer.countEntities()); }); }); @@ -97,9 +101,9 @@ public class EntityRepositoryImpl implements EntityRepository { } private RoomContainer getRoomContainer(Room room) { - return containerRepository.findById(room.getInstanceIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier())) - .findRoomById(room.getIdentifier()) - .orElseThrow(() -> new RoomNotFoundException(room.getInstanceIdentifier(), room.getIdentifier())); + return containerRepository.findById(room.getInstance().getId()) + .orElseThrow(() -> DoesNotExistsException.forInstance(room.getInstance().getId())) + .findRoomById(room.getId()) + .orElseThrow(() -> DoesNotExistsException.forRoom(room.getId())); } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/InstanceRepositoryImpl.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/InstanceRepositoryImpl.java index 94b340a..952f92b 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/InstanceRepositoryImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/InstanceRepositoryImpl.java @@ -2,8 +2,9 @@ package ru.dragonestia.picker.repository.impl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.repository.InstanceRepository; import ru.dragonestia.picker.repository.impl.container.InstanceContainer; @@ -17,18 +18,18 @@ public class InstanceRepositoryImpl implements InstanceRepository { private final ContainerRepository containerRepository; @Override - public void create(Instance instance) throws InstanceAlreadyExistException { + public void create(Instance instance) throws AlreadyExistsException { containerRepository.create(instance); } @Override - public void delete(Instance instance) { - containerRepository.remove(instance.getIdentifier()); + public void delete(InstanceId instanceId) { + containerRepository.remove(instanceId); } @Override - public Optional findById(String nodeId) { - return containerRepository.findById(nodeId).map(InstanceContainer::getInstance); + public Optional findById(InstanceId id) { + return containerRepository.findById(id).map(InstanceContainer::getInstance); } @Override diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/RoomRepositoryImpl.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/RoomRepositoryImpl.java index c6bc532..78fdeaa 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/RoomRepositoryImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/RoomRepositoryImpl.java @@ -2,12 +2,13 @@ package ru.dragonestia.picker.repository.impl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import ru.dragonestia.picker.api.exception.NoRoomsAvailableException; -import ru.dragonestia.picker.api.exception.InstanceNotFoundException; -import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; -import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.DoesNotExistsException; +import ru.dragonestia.picker.exception.NoRoomsAvailableException; +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.model.room.Room; -import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.room.RoomId; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.repository.impl.container.RoomContainer; @@ -22,39 +23,39 @@ public class RoomRepositoryImpl implements RoomRepository { private final ContainerRepository containerRepository; @Override - public void create(Room room) throws RoomAlreadyExistException { - containerRepository.findById(room.getInstanceIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier())) + public void create(Room room) throws AlreadyExistsException { + containerRepository.findById(room.getInstance().getId()) + .orElseThrow(() -> DoesNotExistsException.forInstance(room.getInstance().getId())) .addRoom(room); } @Override - public void remove(Room room) { - containerRepository.findById(room.getInstanceIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier())) - .removeRoom(room); + public void remove(InstanceId instanceId, RoomId roomId) { + containerRepository.findById(instanceId) + .orElseThrow(() -> DoesNotExistsException.forInstance(instanceId)) + .removeRoom(roomId); } @Override - public Optional find(Instance instance, String identifier) { - return containerRepository.findById(instance.getIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier())) - .findRoomById(identifier) + public Optional find(InstanceId instanceId, RoomId roomId) { + return containerRepository.findById(instanceId) + .orElseThrow(() -> DoesNotExistsException.forInstance(instanceId)) + .findRoomById(roomId) .map(RoomContainer::getRoom); } @Override - public Collection all(Instance instance) { - return containerRepository.findById(instance.getIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier())) + public Collection all(InstanceId instanceId) { + return containerRepository.findById(instanceId) + .orElseThrow(() -> DoesNotExistsException.forInstance(instanceId)) .allRooms() .stream().map(RoomContainer::getRoom).toList(); } @Override - public Room pick(Instance instance, Set entities) throws NoRoomsAvailableException { - return containerRepository.findById(instance.getIdentifier()) - .orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier())) + public Room pick(InstanceId instanceId, Set entities) throws NoRoomsAvailableException { + return containerRepository.findById(instanceId) + .orElseThrow(() -> DoesNotExistsException.forInstance(instanceId)) .pick(entities); } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/container/InstanceContainer.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/container/InstanceContainer.java index 2507a26..67e4573 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/container/InstanceContainer.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/container/InstanceContainer.java @@ -1,11 +1,12 @@ package ru.dragonestia.picker.repository.impl.container; import lombok.Getter; -import org.jetbrains.annotations.NotNull; -import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.instance.Instance; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.room.RoomId; import ru.dragonestia.picker.repository.impl.picker.LeastPickedPicker; import ru.dragonestia.picker.repository.impl.picker.RoomPicker; import ru.dragonestia.picker.repository.impl.picker.RoundRobinPicker; @@ -19,21 +20,20 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; public class InstanceContainer { - @Getter - private final Instance instance; + @Getter private final Instance instance; private final EntityTransaction.Listener transactionListener; - private final RoomPicker picker; + @Getter private final RoomPicker picker; private final ReadWriteLock roomLock = new ReentrantReadWriteLock(); - private final Map rooms = new ConcurrentHashMap<>(); + private final Map rooms = new ConcurrentHashMap<>(); - public InstanceContainer(@NotNull Instance instance, @NotNull EntityTransaction.Listener transactionListener) { + public InstanceContainer(Instance instance, EntityTransaction.Listener transactionListener) { this.instance = instance; this.transactionListener = transactionListener; this.picker = initPicker(); } - private @NotNull RoomPicker initPicker() { + private RoomPicker initPicker() { return switch (instance.getPickingMethod()) { case SEQUENTIAL_FILLING -> new SequentialFillingPicker(this); case ROUND_ROBIN -> new RoundRobinPicker(this); @@ -41,31 +41,31 @@ public class InstanceContainer { }; } - public void addRoom(Room room) throws RoomAlreadyExistException { + public void addRoom(Room room) throws AlreadyExistsException { roomLock.writeLock().lock(); try { - if (rooms.containsKey(room.getIdentifier())) { - throw new RoomAlreadyExistException(instance.getIdentifier(), room.getIdentifier()); + if (rooms.containsKey(room.getId())) { + throw AlreadyExistsException.forRoom(instance.getId(), room.getId()); } var container = new RoomContainer(room, this); - rooms.put(room.getIdentifier(), container); + rooms.put(room.getId(), container); picker.add(container); } finally { roomLock.writeLock().unlock(); } } - public void removeRoom(@NotNull Room room) { + public void removeRoom(RoomId roomId) { roomLock.writeLock().lock(); try { - picker.remove(rooms.remove(room.getIdentifier())); + picker.remove(rooms.remove(roomId)); } finally { roomLock.writeLock().unlock(); } } - public void removeRoomsByIds(@NotNull Collection roomIds) { + public void removeRoomsByIds(Collection roomIds) { roomLock.writeLock().lock(); try { roomIds.forEach(roomId -> picker.remove(rooms.remove(roomId))); @@ -74,7 +74,7 @@ public class InstanceContainer { } } - public @NotNull Optional findRoomById(@NotNull String roomId) { + public Optional findRoomById(RoomId roomId) { roomLock.readLock().lock(); try { return Optional.ofNullable(rooms.get(roomId)); @@ -83,7 +83,7 @@ public class InstanceContainer { } } - public @NotNull Collection allRooms() { + public Collection allRooms() { roomLock.readLock().lock(); try { return rooms.values(); @@ -92,16 +92,16 @@ public class InstanceContainer { } } - public @NotNull Room pick(@NotNull Set entities) { + public Room pick(Set entities) { + var entitiesObj = entities.stream() + .map(Entity::new) + .toList(); // TODO: find entities + synchronized (picker) { - var room = picker.pick(entities); - room.addEntities(entities, false); - transactionListener.accept(new EntityTransaction(room.getRoom(), entities)); + var room = picker.pick(entitiesObj); + room.addEntities(entitiesObj, false); + transactionListener.accept(new EntityTransaction(room.getRoom(), entitiesObj)); return room.getRoom(); } } - - public @NotNull RoomPicker getPicker() { - return picker; - } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/container/RoomContainer.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/container/RoomContainer.java index ae67219..5024661 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/container/RoomContainer.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/container/RoomContainer.java @@ -2,7 +2,7 @@ package ru.dragonestia.picker.repository.impl.container; import lombok.Getter; import org.jetbrains.annotations.NotNull; -import ru.dragonestia.picker.api.exception.RoomAreFullException; +import ru.dragonestia.picker.exception.RoomAreFullException; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; import ru.dragonestia.picker.repository.impl.picker.LeastPickedPicker; @@ -32,7 +32,7 @@ public class RoomContainer { entities.addAll(toAdd); noticePickersAboutEntityNumberUpdate(); } else { - throw new RoomAreFullException(room.getInstanceIdentifier(), room.getIdentifier()); + throw new RoomAreFullException(room.getInstance().getId(), room.getId()); } } finally { entityLock.writeLock().unlock(); @@ -75,7 +75,7 @@ public class RoomContainer { } private boolean canAdd0(int entities) { - return room.hasUnlimitedSlots() || entities + countEntities() <= room.getMaxSlots(); + return room.getSlots() == -1 || entities + countEntities() <= room.getSlots(); } public boolean canAdd(int entities) { diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/LeastPickedPicker.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/LeastPickedPicker.java index b1e8a72..5dbef66 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/LeastPickedPicker.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/LeastPickedPicker.java @@ -1,8 +1,8 @@ package ru.dragonestia.picker.repository.impl.picker; import lombok.RequiredArgsConstructor; -import ru.dragonestia.picker.api.exception.NoRoomsAvailableException; -import ru.dragonestia.picker.api.model.node.PickingMethod; +import ru.dragonestia.picker.exception.NoRoomsAvailableException; +import ru.dragonestia.picker.model.instance.type.PickingMethod; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; import ru.dragonestia.picker.repository.impl.collection.DynamicSortedMap; @@ -27,7 +27,7 @@ public class LeastPickedPicker implements RoomPicker { @Override public void remove(RoomContainer container) { synchronized (map) { - map.removeById(container.getRoom().getIdentifier()); + map.removeById(container.getRoom().getId().getValue()); } } @@ -41,7 +41,7 @@ public class LeastPickedPicker implements RoomPicker { if (!wrapper.canAddUnits(entities.size())) throw new RuntimeException(); } catch (RuntimeException ex) { - throw new NoRoomsAvailableException(container.getInstance().getIdentifier()); + throw new NoRoomsAvailableException(container.getInstance().getId()); } } @@ -50,7 +50,7 @@ public class LeastPickedPicker implements RoomPicker { public void updateEntitiesAmount(Room room, int users) { synchronized (map) { - map.updateItem(room.getIdentifier(), prevValue -> users); + map.updateItem(room.getId().getValue(), prevValue -> users); } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomPicker.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomPicker.java index 1b74503..547ef42 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomPicker.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomPicker.java @@ -1,7 +1,7 @@ package ru.dragonestia.picker.repository.impl.picker; -import ru.dragonestia.picker.api.model.node.PickingMethod; import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.instance.type.PickingMethod; import ru.dragonestia.picker.repository.impl.container.RoomContainer; public interface RoomPicker extends Picker { diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomWrapper.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomWrapper.java index 7168984..e42bc12 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomWrapper.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoomWrapper.java @@ -17,7 +17,7 @@ public class RoomWrapper implements ItemWrapper, QueuedLinkedList @Override public String getId() { - return container.getRoom().getIdentifier(); + return container.getRoom().getId().getValue(); } @Override @@ -27,7 +27,7 @@ public class RoomWrapper implements ItemWrapper, QueuedLinkedList @Override public int maxUnits() { - return container.getRoom().getMaxSlots(); + return container.getRoom().getSlots(); } @Override diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoundRobinPicker.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoundRobinPicker.java index 892d25b..48ffaef 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoundRobinPicker.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/RoundRobinPicker.java @@ -1,9 +1,9 @@ package ru.dragonestia.picker.repository.impl.picker; import lombok.RequiredArgsConstructor; -import ru.dragonestia.picker.api.exception.NoRoomsAvailableException; -import ru.dragonestia.picker.api.model.node.PickingMethod; +import ru.dragonestia.picker.exception.NoRoomsAvailableException; import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.instance.type.PickingMethod; import ru.dragonestia.picker.repository.impl.collection.QueuedLinkedList; import ru.dragonestia.picker.repository.impl.container.InstanceContainer; import ru.dragonestia.picker.repository.impl.container.RoomContainer; @@ -28,7 +28,7 @@ public class RoundRobinPicker implements RoomPicker { @Override public void remove(RoomContainer container) { synchronized (list) { - list.removeById(container.getRoom().getIdentifier()); + list.removeById(container.getRoom().getId().getValue()); } } @@ -42,7 +42,7 @@ public class RoundRobinPicker implements RoomPicker { addition.set(amount); wrapper = list.pick(); } catch (RuntimeException ex) { - throw new NoRoomsAvailableException(container.getInstance().getIdentifier()); + throw new NoRoomsAvailableException(container.getInstance().getId()); } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/SequentialFillingPicker.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/SequentialFillingPicker.java index 15cbd2a..625c10e 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/SequentialFillingPicker.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/picker/SequentialFillingPicker.java @@ -1,9 +1,9 @@ package ru.dragonestia.picker.repository.impl.picker; import lombok.RequiredArgsConstructor; -import ru.dragonestia.picker.api.exception.NoRoomsAvailableException; -import ru.dragonestia.picker.api.model.node.PickingMethod; +import ru.dragonestia.picker.exception.NoRoomsAvailableException; import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.instance.type.PickingMethod; import ru.dragonestia.picker.repository.impl.container.InstanceContainer; import ru.dragonestia.picker.repository.impl.container.RoomContainer; @@ -20,14 +20,14 @@ public class SequentialFillingPicker implements RoomPicker { @Override public void add(RoomContainer container) { synchronized (wrappers) { - wrappers.put(container.getRoom().getIdentifier(), new RoomWrapper(container)); + wrappers.put(container.getRoom().getId().getValue(), new RoomWrapper(container)); } } @Override public void remove(RoomContainer container) { synchronized (wrappers) { - wrappers.remove(container.getRoom().getIdentifier()); + wrappers.remove(container.getRoom().getId()); } } @@ -43,7 +43,7 @@ public class SequentialFillingPicker implements RoomPicker { } } - throw new NoRoomsAvailableException(container.getInstance().getIdentifier()); + throw new NoRoomsAvailableException(container.getInstance().getId()); } @Override diff --git a/server/src/main/java/ru/dragonestia/picker/service/AccountService.java b/server/src/main/java/ru/dragonestia/picker/service/AccountService.java index 5a34655..3076410 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/AccountService.java +++ b/server/src/main/java/ru/dragonestia/picker/service/AccountService.java @@ -1,10 +1,10 @@ package ru.dragonestia.picker.service; -import org.jetbrains.annotations.NotNull; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import ru.dragonestia.picker.model.account.Account; +import ru.dragonestia.picker.model.account.AccountId; import java.util.Collection; import java.util.Optional; @@ -12,18 +12,18 @@ import java.util.Optional; public interface AccountService extends UserDetailsService { @PreAuthorize("hasRole('ADMIN')") - @NotNull Account createNewAccount(@NotNull String username, @NotNull String password); + Account createNewAccount(AccountId id, String password); - @NotNull Optional findAccount(@NotNull String accountId); + Optional findAccount(String accountId); @PreAuthorize("hasRole('ADMIN')") - @NotNull Collection allAccounts(); + Collection allAccounts(); @PreAuthorize("hasRole('ADMIN')") - void removeAccount(@NotNull Account account); + void removeAccount(Account account); @PreAuthorize("hasRole('ADMIN') || principal.username.equals(account.username)") - void updateState(@NotNull Account account); + void updateState(Account account); @Override Account loadUserByUsername(String username) throws UsernameNotFoundException; diff --git a/server/src/main/java/ru/dragonestia/picker/service/EntityService.java b/server/src/main/java/ru/dragonestia/picker/service/EntityService.java index 05e1d7a..4e9ad76 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/EntityService.java +++ b/server/src/main/java/ru/dragonestia/picker/service/EntityService.java @@ -1,7 +1,7 @@ package ru.dragonestia.picker.service; -import ru.dragonestia.picker.api.exception.RoomAreFullException; -import ru.dragonestia.picker.api.model.user.ResponseUser; +import ru.dragonestia.picker.exception.RoomAreFullException; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; @@ -10,15 +10,13 @@ import java.util.List; public interface EntityService { - Collection getEntityRooms(Entity entity); + Collection getEntityRooms(EntityId id); - void linkEntitiesWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException; + void linkEntitiesWithRoom(Room room, Collection entities, boolean force) throws RoomAreFullException; - void unlinkEntitiesFromRoom(Room room, Collection entities); + void unlinkEntitiesFromRoom(Room room, Collection entities); Collection getRoomEntities(Room room); - List searchEntities(String input); - - ResponseUser getEntityDetails(String userId); + List searchEntities(EntityId input); } diff --git a/server/src/main/java/ru/dragonestia/picker/service/InstanceService.java b/server/src/main/java/ru/dragonestia/picker/service/InstanceService.java index 2e0ad8c..dcedbe8 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/InstanceService.java +++ b/server/src/main/java/ru/dragonestia/picker/service/InstanceService.java @@ -1,9 +1,10 @@ package ru.dragonestia.picker.service; import org.springframework.security.access.prepost.PreAuthorize; -import ru.dragonestia.picker.api.exception.InvalidInstanceIdentifierException; -import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.InvalidIdentifierException; import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.instance.InstanceId; import java.util.List; import java.util.Optional; @@ -11,12 +12,12 @@ import java.util.Optional; public interface InstanceService { @PreAuthorize("hasRole('NODE_MANAGEMENT')") - void create(Instance instance) throws InvalidInstanceIdentifierException, InstanceAlreadyExistException; + void create(Instance instance) throws InvalidIdentifierException, AlreadyExistsException; @PreAuthorize("hasRole('NODE_MANAGEMENT')") void remove(Instance instance); List all(); - Optional find(String nodeId); + Optional find(InstanceId id); } diff --git a/server/src/main/java/ru/dragonestia/picker/service/RoomService.java b/server/src/main/java/ru/dragonestia/picker/service/RoomService.java index 64f5855..1f3a51b 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/RoomService.java +++ b/server/src/main/java/ru/dragonestia/picker/service/RoomService.java @@ -1,11 +1,11 @@ package ru.dragonestia.picker.service; -import ru.dragonestia.picker.api.exception.InvalidRoomIdentifierException; -import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; -import ru.dragonestia.picker.api.repository.response.PickedRoomResponse; -import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.InvalidIdentifierException; +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.model.room.Room; -import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.room.RoomId; import java.util.Collection; import java.util.Optional; @@ -13,15 +13,15 @@ import java.util.Set; public interface RoomService { - void create(Room room) throws InvalidRoomIdentifierException, RoomAlreadyExistException; + void create(Room room) throws InvalidIdentifierException, AlreadyExistsException; void remove(Room room); - Optional find(Instance instance, String roomId); + Optional find(InstanceId instanceId, RoomId roomId); - Collection all(Instance instance); + Collection all(InstanceId instanceId); - PickedRoomResponse pickAvailable(Instance instance, Set entities); + Room pick(InstanceId instanceId, Set entities); void updateState(Room room); } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java index c8ae19d..389b14c 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java @@ -2,13 +2,13 @@ package ru.dragonestia.picker.service.impl; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.NotNull; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import ru.dragonestia.picker.api.exception.ConstantAdminParamsException; import ru.dragonestia.picker.config.RoomPickerServerConfig; +import ru.dragonestia.picker.exception.AdminAccountMutationException; import ru.dragonestia.picker.model.account.Account; +import ru.dragonestia.picker.model.account.AccountId; import ru.dragonestia.picker.model.account.Permission; import ru.dragonestia.picker.service.AccountService; @@ -30,39 +30,39 @@ public class AccountServiceImpl implements AccountService { @PostConstruct void init() { - var account = createNewAccount(adminCredentials.username(), adminCredentials.password()); + var account = createNewAccount(AccountId.of(adminCredentials.username()), adminCredentials.password()); account.setAuthorities(Arrays.stream(Permission.values()).collect(Collectors.toSet())); - createNewAccount("test", "qwerty123"); + createNewAccount(AccountId.of("test"), "qwerty123"); } - public @NotNull Account createNewAccount(@NotNull String username, @NotNull String password) { - var account = new Account(username, passwordEncoder.encode(password)); + public Account createNewAccount(AccountId id, String password) { + var account = new Account(id, passwordEncoder.encode(password)); accounts.put(account.getUsername().toLowerCase(), account); return account; } @Override - public @NotNull Optional findAccount(@NotNull String accountId) { + public Optional findAccount(String accountId) { return Optional.ofNullable(accounts.getOrDefault(accountId, null)); } @Override - public @NotNull Collection allAccounts() { + public Collection allAccounts() { return accounts.values().stream() .filter(account -> !adminCredentials.username().equals(account.getUsername())) .toList(); } @Override - public void removeAccount(@NotNull Account account) { + public void removeAccount(Account account) { checkAdmin(account.getUsername()); accounts.remove(account.getUsername()); account.setEnabled(false); } @Override - public void updateState(@NotNull Account account) { + public void updateState(Account account) { checkAdmin(account.getUsername()); // TODO: save data to local storage } @@ -79,7 +79,7 @@ public class AccountServiceImpl implements AccountService { private void checkAdmin(String accountId) { if (adminCredentials.username().equals(accountId)) { - throw new ConstantAdminParamsException(); + throw new AdminAccountMutationException(); } } } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/EntityServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/EntityServiceImpl.java index fce0296..4d17b3f 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/EntityServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/EntityServiceImpl.java @@ -2,7 +2,7 @@ package ru.dragonestia.picker.service.impl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import ru.dragonestia.picker.api.model.user.ResponseUser; +import ru.dragonestia.picker.model.entity.EntityId; import ru.dragonestia.picker.model.room.Room; import ru.dragonestia.picker.model.entity.Entity; import ru.dragonestia.picker.repository.EntityRepository; @@ -17,17 +17,17 @@ public class EntityServiceImpl implements EntityService { private final EntityRepository entityRepository; @Override - public Collection getEntityRooms(Entity entity) { - return entityRepository.findAllLinkedEntityRooms(entity); + public Collection getEntityRooms(EntityId id) { + return entityRepository.findAllLinkedEntityRooms(id); } @Override - public void linkEntitiesWithRoom(Room room, Collection entities, boolean force) { + public void linkEntitiesWithRoom(Room room, Collection entities, boolean force) { entityRepository.linkWithRoom(room, entities, force); } @Override - public void unlinkEntitiesFromRoom(Room room, Collection entities) { + public void unlinkEntitiesFromRoom(Room room, Collection entities) { entityRepository.unlinkWithRoom(room, entities); } @@ -37,12 +37,7 @@ public class EntityServiceImpl implements EntityService { } @Override - public List searchEntities(String input) { - return entityRepository.search(input).stream().map(Entity::toResponseObject).toList(); - } - - @Override - public ResponseUser getEntityDetails(String userId) { - throw new UnsupportedOperationException("Not implemented"); + public List searchEntities(EntityId input) { + return entityRepository.search(input).stream().toList(); } } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/InstanceServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/InstanceServiceImpl.java index fb4b550..6bb30ad 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/InstanceServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/InstanceServiceImpl.java @@ -2,9 +2,10 @@ package ru.dragonestia.picker.service.impl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import ru.dragonestia.picker.api.exception.InvalidInstanceIdentifierException; -import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.InvalidIdentifierException; import ru.dragonestia.picker.model.instance.Instance; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.repository.InstanceRepository; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.service.InstanceService; @@ -22,18 +23,18 @@ public class InstanceServiceImpl implements InstanceService { private final InstanceAndRoomStorage storage; @Override - public void create(Instance instance) throws InvalidInstanceIdentifierException, InstanceAlreadyExistException { + public void create(Instance instance) throws InvalidIdentifierException, AlreadyExistsException { instanceRepository.create(instance); storage.saveInstance(instance); } @Override public void remove(Instance instance) { - for (var room: roomRepository.all(instance)) { + for (var room: roomRepository.all(instance.getId())) { storage.removeRoom(room); } - instanceRepository.delete(instance); + instanceRepository.delete(instance.getId()); storage.removeInstance(instance); } @@ -43,7 +44,7 @@ public class InstanceServiceImpl implements InstanceService { } @Override - public Optional find(String nodeId) { - return instanceRepository.findById(nodeId); + public Optional find(InstanceId id) { + return instanceRepository.findById(id); } } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/RoomServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/RoomServiceImpl.java index 0c7d181..7412b9f 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/RoomServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/RoomServiceImpl.java @@ -3,14 +3,14 @@ package ru.dragonestia.picker.service.impl; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; -import ru.dragonestia.picker.api.exception.InvalidRoomIdentifierException; -import ru.dragonestia.picker.api.exception.InstanceNotFoundException; -import ru.dragonestia.picker.api.exception.NotPersistedNodeException; -import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; -import ru.dragonestia.picker.api.repository.response.PickedRoomResponse; +import ru.dragonestia.picker.exception.AlreadyExistsException; +import ru.dragonestia.picker.exception.ConflictingPersistParametersException; +import ru.dragonestia.picker.exception.DoesNotExistsException; +import ru.dragonestia.picker.exception.InvalidIdentifierException; +import ru.dragonestia.picker.model.entity.EntityId; +import ru.dragonestia.picker.model.instance.InstanceId; import ru.dragonestia.picker.model.room.Room; -import ru.dragonestia.picker.model.instance.Instance; -import ru.dragonestia.picker.model.entity.Entity; +import ru.dragonestia.picker.model.room.RoomId; import ru.dragonestia.picker.repository.InstanceRepository; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.repository.EntityRepository; @@ -18,7 +18,6 @@ import ru.dragonestia.picker.service.RoomService; import ru.dragonestia.picker.storage.InstanceAndRoomStorage; import java.util.*; -import java.util.stream.Collectors; @Log4j2 @Service @@ -31,10 +30,12 @@ public class RoomServiceImpl implements RoomService { private final InstanceAndRoomStorage storage; @Override - public void create(Room room) throws InvalidRoomIdentifierException, RoomAlreadyExistException, NotPersistedNodeException { - var node = instanceRepository.findById(room.getInstanceIdentifier()).orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier())); - if (!node.isPersist() && room.isPersist()) { - throw new NotPersistedNodeException(node.getIdentifier(), room.getIdentifier()); + public void create(Room room) throws InvalidIdentifierException, AlreadyExistsException, ConflictingPersistParametersException { + var instance = instanceRepository.findById(room.getInstance().getId()) + .orElseThrow(() -> DoesNotExistsException.forInstance(room.getInstance().getId())); + + if (!instance.isPersist() && room.isPersist()) { + throw ConflictingPersistParametersException.forRoom(instance.getId(), room.getId()); } roomRepository.create(room); @@ -43,34 +44,23 @@ public class RoomServiceImpl implements RoomService { @Override public void remove(Room room) { - roomRepository.remove(room); + roomRepository.remove(room.getInstance().getId(), room.getId()); storage.removeRoom(room); } @Override - public Optional find(Instance instance, String roomId) { - return roomRepository.find(instance, roomId); + public Optional find(InstanceId instanceId, RoomId roomId) { + return roomRepository.find(instanceId, roomId); } @Override - public Collection all(Instance instance) { - return roomRepository.all(instance); + public Collection all(InstanceId instanceId) { + return roomRepository.all(instanceId); } @Override - public PickedRoomResponse pickAvailable(Instance instance, Set entities) { - var room = roomRepository.pick(instance, entities); - var roomUsers = entityRepository.entitiesOf(room); - - return new PickedRoomResponse( - room.getInstanceIdentifier(), - room.getIdentifier(), - room.getPayload(), - room.getMaxSlots(), - roomUsers.size(), - room.isLocked(), - roomUsers.stream().map(Entity::getIdentifier).collect(Collectors.toSet()) - ); + public Room pick(InstanceId instanceId, Set entities) { + return roomRepository.pick(instanceId, entities); } @Override diff --git a/server/src/main/java/ru/dragonestia/picker/storage/impl/FileStorageImpl.java b/server/src/main/java/ru/dragonestia/picker/storage/impl/FileStorageImpl.java index 21ca0ac..5844166 100644 --- a/server/src/main/java/ru/dragonestia/picker/storage/impl/FileStorageImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/storage/impl/FileStorageImpl.java @@ -66,7 +66,7 @@ public class FileStorageImpl implements InstanceAndRoomStorage { @Override public void saveInstance(Instance instance) { if (!instance.isPersist()) return; - var instanceFile = new File(path + "/instances/" + instance.getIdentifier() + ".json"); + var instanceFile = new File(path + "/instances/" + instance.getId() + ".json"); var writer = objectMapper.writer(); try { @@ -79,16 +79,16 @@ public class FileStorageImpl implements InstanceAndRoomStorage { @Override public void removeInstance(Instance instance) { if (!instance.isPersist()) return; - new File(path + "/nodes/" + instance.getIdentifier() + ".json").delete(); + new File(path + "/nodes/" + instance.getId() + ".json").delete(); - log.info("Removed instance '%s' from disk storage".formatted(instance.getIdentifier())); + log.info("Removed instance '%s' from disk storage".formatted(instance.getId())); } @SneakyThrows @Override public void saveRoom(Room room) { if (!room.isPersist()) return; - var roomFile = new File("%s/rooms/%s.%s.json".formatted(path, room.getInstanceIdentifier(), room.getIdentifier())); + var roomFile = new File("%s/rooms/%s.%s.json".formatted(path, room.getInstance().getId(), room.getId())); var writer = objectMapper.writer(); try { @@ -101,8 +101,8 @@ public class FileStorageImpl implements InstanceAndRoomStorage { @Override public void removeRoom(Room room) { if (!room.isPersist()) return; - new File("%s/rooms/%s.%s.json".formatted(path, room.getInstanceIdentifier(), room.getIdentifier())).delete(); + new File("%s/rooms/%s.%s.json".formatted(path, room.getInstance().getId(), room.getId())).delete(); - log.info("Removed room '%s/%s' from disk storage".formatted(room.getInstanceIdentifier(), room.getIdentifier())); + log.info("Removed room '%s/%s' from disk storage".formatted(room.getInstance().getId(), room.getId())); } } diff --git a/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java b/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java index 97ad1d6..511d345 100644 --- a/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java +++ b/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java @@ -9,7 +9,7 @@ import ru.dragonestia.picker.api.repository.type.RoomIdentifier; import ru.dragonestia.picker.api.repository.type.EntityIdentifier; import ru.dragonestia.picker.model.instance.Instance; import ru.dragonestia.picker.model.entity.Entity; -import ru.dragonestia.picker.model.factory.RoomFactory; +import ru.dragonestia.picker.model.room.factory.RoomFactory; import ru.dragonestia.picker.repository.InstanceRepository; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.repository.EntityRepository; diff --git a/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java b/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java index ff63eae..dcdc533 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java @@ -48,8 +48,8 @@ public class LeastPickedTests { var users = entityRepository.entitiesOf(room); Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - System.out.printf("Room(%s) has %s/%s users. Expected: %s(%s), added: %s%n", room.getIdentifier(), users.size(), slots, expectedRoomId, expectedRoomUsers, usersAmount); - Assertions.assertEquals(expectedRoomId, room.getIdentifier()); + System.out.printf("Room(%s) has %s/%s users. Expected: %s(%s), added: %s%n", room.getId(), users.size(), slots, expectedRoomId, expectedRoomUsers, usersAmount); + Assertions.assertEquals(expectedRoomId, room.getId()); } public static class PickingArgumentProvider implements ArgumentsProvider { diff --git a/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java b/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java index 1095905..476e8cc 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java @@ -44,7 +44,7 @@ public class RoundRobinTests { var users = entityRepository.entitiesOf(room); Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - Assertions.assertEquals(expectedRoomId, room.getIdentifier()); + Assertions.assertEquals(expectedRoomId, room.getId()); } public static class PickingArgumentProvider implements ArgumentsProvider { diff --git a/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java b/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java index a68a540..1dfa368 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java @@ -48,8 +48,8 @@ public class SequentialFillingTests { var users = entityRepository.entitiesOf(room); Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - System.out.printf("Room(%s) has %s/%s users. Expected: %s(%s), added: %s%n", room.getIdentifier(), users.size(), slots, expectedRoomId, expectedRoomUsers, usersAmount); - Assertions.assertEquals(expectedRoomId, room.getIdentifier()); + System.out.printf("Room(%s) has %s/%s users. Expected: %s(%s), added: %s%n", room.getId(), users.size(), slots, expectedRoomId, expectedRoomUsers, usersAmount); + Assertions.assertEquals(expectedRoomId, room.getId()); } public static class PickingArgumentProvider implements ArgumentsProvider { diff --git a/server/src/test/java/ru/dragonestia/picker/service/InstanceServiceTests.java b/server/src/test/java/ru/dragonestia/picker/service/InstanceServiceTests.java index b1683de..41d3220 100644 --- a/server/src/test/java/ru/dragonestia/picker/service/InstanceServiceTests.java +++ b/server/src/test/java/ru/dragonestia/picker/service/InstanceServiceTests.java @@ -24,12 +24,12 @@ public class InstanceServiceTests { var node = new Instance(NodeIdentifier.of("test"), PickingMethod.SEQUENTIAL_FILLING, false); Assertions.assertDoesNotThrow(() -> instanceService.create(node)); - Assertions.assertTrue(instanceService.find(node.getIdentifier()).isPresent()); + Assertions.assertTrue(instanceService.find(node.getId()).isPresent()); Assertions.assertThrows(InstanceAlreadyExistException.class, () -> instanceService.create(node)); instanceService.remove(node); - Assertions.assertFalse(() -> instanceService.find(node.getIdentifier()).isPresent()); + Assertions.assertFalse(() -> instanceService.find(node.getId()).isPresent()); } @WithMockUser(roles = {"NODE_MANAGEMENT"}) diff --git a/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java b/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java index f214af7..1a74401 100644 --- a/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java +++ b/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java @@ -17,7 +17,7 @@ import ru.dragonestia.picker.api.repository.type.RoomIdentifier; import ru.dragonestia.picker.api.repository.type.EntityIdentifier; import ru.dragonestia.picker.model.instance.Instance; import ru.dragonestia.picker.model.entity.Entity; -import ru.dragonestia.picker.model.factory.RoomFactory; +import ru.dragonestia.picker.model.room.factory.RoomFactory; import java.util.List; import java.util.Set; @@ -51,12 +51,12 @@ public class RoomServiceTests { var room = roomFactory.create(RoomIdentifier.of("test-room"), instance, IRoom.UNLIMITED_SLOTS, "", false); roomService.create(room); - Assertions.assertTrue(roomService.find(instance, room.getIdentifier()).isPresent()); + Assertions.assertTrue(roomService.find(instance, room.getId()).isPresent()); Assertions.assertThrows(RoomAlreadyExistException.class, () -> roomService.create(room)); roomService.remove(room); - Assertions.assertFalse(roomService.find(instance, room.getIdentifier()).isPresent()); + Assertions.assertFalse(roomService.find(instance, room.getId()).isPresent()); } @WithMockUser(roles = {"NODE_MANAGEMENT"}) @@ -107,7 +107,7 @@ public class RoomServiceTests { ); - Assertions.assertEquals("test-room4", roomService.pickAvailable(instance, users).roomId()); + Assertions.assertEquals("test-room4", roomService.pick(instance, users).roomId()); } @WithMockUser(roles = {"NODE_MANAGEMENT"}) @@ -127,6 +127,6 @@ public class RoomServiceTests { Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.create(room)); Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.remove(room)); Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.find(node, "Bruh")); - Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.pickAvailable(node, Set.of(new Entity(EntityIdentifier.of("1"))))); + Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.pick(node, Set.of(new Entity(EntityIdentifier.of("1"))))); } }