diff --git a/client-api/src/main/java/ru/dragonestia/picker/api/util/IdentifierValidator.java b/client-api/src/main/java/ru/dragonestia/picker/api/util/IdentifierValidator.java index 4d5ed83..744bb42 100644 --- a/client-api/src/main/java/ru/dragonestia/picker/api/util/IdentifierValidator.java +++ b/client-api/src/main/java/ru/dragonestia/picker/api/util/IdentifierValidator.java @@ -11,7 +11,7 @@ public static boolean forNode(@NotNull String nodeId) { } public static boolean forRoom(@NotNull String roomId) { - return roomId.matches("^(?!-)[a-z\\d-]{0,31}[a-z\\d](?!-)$"); + return roomId.matches("^(?!-)[a-z\\d-]{0,35}[a-z\\d](?!-)$"); } public static boolean forUser(@NotNull String username) { diff --git a/client-api/src/test/java/util/IdentifierValidatorTests.java b/client-api/src/test/java/util/IdentifierValidatorTests.java index 76e8209..a13bc8b 100644 --- a/client-api/src/test/java/util/IdentifierValidatorTests.java +++ b/client-api/src/test/java/util/IdentifierValidatorTests.java @@ -34,8 +34,8 @@ void test_forRooms() { Assertions.assertFalse(IdentifierValidator.forRoom("-")); Assertions.assertFalse(IdentifierValidator.forRoom("-a")); Assertions.assertFalse(IdentifierValidator.forRoom("a-")); - Assertions.assertTrue(IdentifierValidator.forRoom("a".repeat(32))); - Assertions.assertFalse(IdentifierValidator.forRoom("a".repeat(33))); + Assertions.assertTrue(IdentifierValidator.forRoom("a".repeat(36))); + Assertions.assertFalse(IdentifierValidator.forRoom("a".repeat(37))); } @Test diff --git a/server/build.gradle b/server/build.gradle index 7bb57bf..af76d89 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -11,6 +11,7 @@ configurations { dependencies { implementation project(":client-api") + implementation 'org.jetbrains:annotations:24.1.0' 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/config/TestConfig.java b/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java index ef18da4..b6af4be 100644 --- a/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java +++ b/server/src/main/java/ru/dragonestia/picker/config/TestConfig.java @@ -11,6 +11,10 @@ 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.UserIdentifier; import ru.dragonestia.picker.interceptor.DebugInterceptor; import ru.dragonestia.picker.model.Room; import ru.dragonestia.picker.model.Node; @@ -42,9 +46,9 @@ public void addInterceptors(@NonNull InterceptorRegistry registry) { @Bean void createNodes() { - createNodeWithContent(new Node("game-servers", PickingMethod.ROUND_ROBIN, false)); - createNodeWithContent(new Node("game-lobbies", PickingMethod.LEAST_PICKED, false)); - createNodeWithContent(new Node("hub", PickingMethod.SEQUENTIAL_FILLING, false)); + createNodeWithContent(new Node(NodeIdentifier.of("game-servers"), PickingMethod.ROUND_ROBIN, false)); + createNodeWithContent(new Node(NodeIdentifier.of("game-lobbies"), PickingMethod.LEAST_PICKED, false)); + createNodeWithContent(new Node(NodeIdentifier.of("hub"), PickingMethod.SEQUENTIAL_FILLING, false)); } @SneakyThrows @@ -54,17 +58,17 @@ private void createNodeWithContent(Node node) { for (int i = 1; i <= 5; i++) { var slots = 5 * i; - var room = Room.create("test-" + i, node, SlotLimit.of(slots), json.writeValueAsString(generatePayload()), false); + var room = new Room(RoomIdentifier.of("test-" + i), node, slots, json.writeValueAsString(generatePayload()), false); roomRepository.create(room); for (int j = 0, n = rand.nextInt(slots + 1); j < n; j++) { - var user = new User("test-user-" + rand.nextInt(20)); + var user = new User(UserIdentifier.of("test-user-" + rand.nextInt(20))); userRepository.linkWithRoom(room, List.of(user), false); } } for (int i = 0; i < 5; i++) { - var room = Room.create(randomUUID().toString(), node, SlotLimit.unlimited(), json.writeValueAsString(generatePayload()), false); + var room = new Room(RoomIdentifier.of(randomUUID().toString()), node, IRoom.UNLIMITED_SLOTS, json.writeValueAsString(generatePayload()), false); room.setLocked((i & 1) == 0); roomRepository.create(room); } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/NodeController.java b/server/src/main/java/ru/dragonestia/picker/controller/NodeController.java index fb0c3fb..c72a527 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/NodeController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/NodeController.java @@ -11,6 +11,7 @@ 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.api.repository.type.NodeIdentifier; import ru.dragonestia.picker.model.Node; import ru.dragonestia.picker.service.NodeService; import ru.dragonestia.picker.service.RoomService; @@ -45,7 +46,7 @@ ResponseEntity registerNode( @Parameter(description = "Picking method method") @RequestParam(name = "method") PickingMethod method, @Parameter(description = "Save node") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist ) { - nodeService.create(new Node(nodeId, method, persist)); + nodeService.create(new Node(NodeIdentifier.of(nodeId), method, persist)); return ResponseEntity.ok().build(); } 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 d76aac2..5aecb1a 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/RoomController.java @@ -11,8 +11,8 @@ import ru.dragonestia.picker.api.exception.RoomNotFoundException; import ru.dragonestia.picker.api.repository.response.RoomInfoResponse; import ru.dragonestia.picker.api.repository.response.RoomListResponse; +import ru.dragonestia.picker.api.repository.type.RoomIdentifier; import ru.dragonestia.picker.model.Room; -import ru.dragonestia.picker.model.type.SlotLimit; import ru.dragonestia.picker.service.RoomService; import ru.dragonestia.picker.service.NodeService; import ru.dragonestia.picker.util.DetailsParser; @@ -54,7 +54,7 @@ ResponseEntity register( @Parameter(description = "Save room") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist ) { var node = nodeService.find(nodeId).orElseThrow(() -> new NodeNotFoundException(nodeId)); - var room = Room.create(roomId, node, SlotLimit.of(slots), payload, persist); + var room = new Room(RoomIdentifier.of(roomId), node, slots, payload, persist); room.setLocked(locked); roomService.create(room); diff --git a/server/src/main/java/ru/dragonestia/picker/controller/UserController.java b/server/src/main/java/ru/dragonestia/picker/controller/UserController.java index 1afe677..5714aba 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/UserController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/UserController.java @@ -9,6 +9,7 @@ import ru.dragonestia.picker.api.repository.response.LinkedRoomsWithUserResponse; import ru.dragonestia.picker.api.repository.response.SearchUserResponse; import ru.dragonestia.picker.api.repository.response.UserDetailsResponse; +import ru.dragonestia.picker.api.repository.type.UserIdentifier; import ru.dragonestia.picker.model.User; import ru.dragonestia.picker.service.UserService; import ru.dragonestia.picker.util.DetailsParser; @@ -62,6 +63,6 @@ LinkedRoomsWithUserResponse roomsOf( return new LinkedRoomsWithUserResponse(List.of()); } - return new LinkedRoomsWithUserResponse(userService.getUserRoomsWithDetails(new User(userId), detailsParser.parseRoomDetails(detailsSeq))); + return new LinkedRoomsWithUserResponse(userService.getUserRoomsWithDetails(new User(UserIdentifier.of(userId)), detailsParser.parseRoomDetails(detailsSeq))); } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/UserRoomController.java b/server/src/main/java/ru/dragonestia/picker/controller/UserRoomController.java index 3682006..351d7ff 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/UserRoomController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/UserRoomController.java @@ -42,7 +42,7 @@ ResponseEntity usersInsideRoom( var room = getNodeAndRoom(nodeId, roomId).room(); var users = userService.getRoomUsersWithDetailsResponse(room, detailsParser.parseUserDetails(detailsSeq)); - return ResponseEntity.ok(new RoomUserListResponse(room.getSlots().getSlots(), users.size(), users)); + return ResponseEntity.ok(new RoomUserListResponse(room.getMaxSlots(), users.size(), users)); } @Operation(summary = "Link users with room") @@ -56,7 +56,7 @@ ResponseEntity linkUserWithRoom( var room = getNodeAndRoom(nodeId, roomId).room(); var users = namingValidator.validateUserIds(Arrays.stream(userIds.split(",")).toList()); var usedSlots = userService.linkUsersWithRoom(room, users, force); - return ResponseEntity.ok(new LinkUsersWithRoomResponse(usedSlots, room.getSlots().getSlots())); + return ResponseEntity.ok(new LinkUsersWithRoomResponse(usedSlots, room.getMaxSlots())); } @Operation(summary = "Unlink users from room") diff --git a/server/src/main/java/ru/dragonestia/picker/model/Node.java b/server/src/main/java/ru/dragonestia/picker/model/Node.java index 7182eb0..36e704c 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/Node.java +++ b/server/src/main/java/ru/dragonestia/picker/model/Node.java @@ -1,14 +1,52 @@ package ru.dragonestia.picker.model; -import lombok.NonNull; +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; -public record Node(@NonNull String id, @NonNull PickingMethod method, boolean persist) { +public class Node implements INode { + + private final String identifier; + private final PickingMethod pickingMethod; + private final boolean persist; + + public Node(@NotNull NodeIdentifier identifier, @NotNull PickingMethod pickingMethod, boolean persist) { + this.identifier = identifier.getValue(); + 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 id.hashCode(); + return identifier.hashCode(); } @Override @@ -16,12 +54,8 @@ public boolean equals(Object object) { if (object == this) return true; if (object == null) return false; if (object instanceof Node other) { - return id.equals(other.id); + return identifier.equals(other.identifier); } return false; } - - public ResponseNode toResponseObject() { - return new ResponseNode(id, method); - } } diff --git a/server/src/main/java/ru/dragonestia/picker/model/Room.java b/server/src/main/java/ru/dragonestia/picker/model/Room.java index 5f7773a..a4ea965 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/Room.java +++ b/server/src/main/java/ru/dragonestia/picker/model/Room.java @@ -1,42 +1,86 @@ package ru.dragonestia.picker.model; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +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.model.type.SlotLimit; +import ru.dragonestia.picker.api.repository.type.RoomIdentifier; -import java.util.HashMap; +public class Room implements IRoom { -@Getter -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class Room { - - private final String id; - private final String nodeId; - private final SlotLimit slots; + private final String identifier; + private final String nodeIdentifier; + private final int slots; private final String payload; private final boolean persist; private boolean locked = false; - public static Room create(String roomId, Node node, SlotLimit limit, String payload, boolean persist) { - return new Room(roomId, node.id(), limit, payload, persist); + public Room(@NotNull RoomIdentifier identifier, @NotNull Node node, int slots, @NotNull String payload, boolean persist) { + this.identifier = identifier.getValue(); + this.nodeIdentifier = node.getIdentifier(); + this.slots = slots; + this.payload = payload; + this.persist = persist; + } + + @Override + public @NotNull String getIdentifier() { + return identifier; + } + + @Override + public @NotNull String getNodeIdentifier() { + return nodeIdentifier; + } + + @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 (slots.isUnlimited()) return true; - return slots.getSlots() >= usedSlots + requiredSlots; + if (hasUnlimitedSlots()) return true; + return slots >= usedSlots + requiredSlots; + } + + public @NotNull ResponseRoom toResponseObject() { + return new ResponseRoom(identifier, nodeIdentifier, slots, locked, payload); + } + + public @NotNull ShortResponseRoom toShortResponseObject() { + return new ShortResponseRoom(identifier, nodeIdentifier, slots, locked); } @Override public int hashCode() { - return id.hashCode(); + return identifier.hashCode(); } @Override @@ -44,16 +88,8 @@ public boolean equals(Object object) { if (object == this) return true; if (object == null) return false; if (object instanceof Room other) { - return id.equals(other.id); + return identifier.equals(other.identifier); } return false; } - - public ResponseRoom toResponseObject() { - return new ResponseRoom(id, nodeId, slots.getSlots(), locked, payload); - } - - public ShortResponseRoom toShortResponseObject() { - return new ShortResponseRoom(id, nodeId, slots.getSlots(), locked); - } } diff --git a/server/src/main/java/ru/dragonestia/picker/model/User.java b/server/src/main/java/ru/dragonestia/picker/model/User.java index f28f5c7..1af895b 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/User.java +++ b/server/src/main/java/ru/dragonestia/picker/model/User.java @@ -1,13 +1,37 @@ package ru.dragonestia.picker.model; -import lombok.NonNull; +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.UserIdentifier; -public record User(@NonNull String id) { +public class User implements IUser { + + private final String identifier; + + public User(@NotNull UserIdentifier 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); + } @Override public int hashCode() { - return id.hashCode(); + return identifier.hashCode(); } @Override @@ -15,12 +39,8 @@ public boolean equals(Object object) { if (object == this) return true; if (object == null) return false; if (object instanceof User other) { - return id.equals(other.id); + return identifier.equals(other.identifier); } return false; } - - public ResponseUser toResponseObject() { - return new ResponseUser(id); - } } diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/NodeRepositoryImpl.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/NodeRepositoryImpl.java index 2a34b35..defb133 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/NodeRepositoryImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/NodeRepositoryImpl.java @@ -9,10 +9,12 @@ import ru.dragonestia.picker.repository.NodeRepository; import ru.dragonestia.picker.repository.impl.cache.NodeId2PickerModeCache; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; @Repository @RequiredArgsConstructor @@ -21,45 +23,58 @@ public class NodeRepositoryImpl implements NodeRepository { private final RoomRepository roomRepository; private final PickerRepository pickerRepository; private final NodeId2PickerModeCache nodeId2PickerModeCache; - private final Map nodeMap = new ConcurrentHashMap<>(); + private final Map nodeMap = new HashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); @Override public void create(Node node) throws NodeAlreadyExistException { - synchronized (nodeMap) { - if (nodeMap.containsKey(node.id())) { - throw new NodeAlreadyExistException(node.id()); + lock.writeLock().lock(); + try { + if (nodeMap.containsKey(node.getIdentifier())) { + throw new NodeAlreadyExistException(node.getIdentifier()); } - nodeMap.put(node.id(), node); - var picker = pickerRepository.create(node.id(), node.method()); - nodeId2PickerModeCache.put(node.id(), picker); - } + nodeMap.put(node.getIdentifier(), node); + var picker = pickerRepository.create(node.getIdentifier(), node.getPickingMethod()); + nodeId2PickerModeCache.put(node.getIdentifier(), picker); - roomRepository.onCreateNode(node); + roomRepository.onCreateNode(node); + } finally { + lock.writeLock().unlock(); + } } @Override public List delete(Node node) { - synchronized (nodeMap) { - nodeMap.remove(node.id()); - pickerRepository.remove(node.id()); - nodeId2PickerModeCache.remove(node.id()); - } + lock.writeLock().lock(); + try { + nodeMap.remove(node.getIdentifier()); + pickerRepository.remove(node.getIdentifier()); + nodeId2PickerModeCache.remove(node.getIdentifier()); - return roomRepository.onRemoveNode(node); + return roomRepository.onRemoveNode(node); + } finally { + lock.writeLock().unlock(); + } } @Override public Optional find(String nodeId) { - synchronized (nodeMap) { + lock.readLock().lock(); + try { return nodeMap.containsKey(nodeId)? Optional.of(nodeMap.get(nodeId)) : Optional.empty(); + } finally { + lock.readLock().unlock(); } } @Override public List all() { - synchronized (nodeMap) { + lock.readLock().lock(); + try { return nodeMap.values().stream().toList(); + } finally { + lock.readLock().unlock(); } } } 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 caf9193..c0d4b0e 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 @@ -11,8 +11,9 @@ import ru.dragonestia.picker.repository.UserRepository; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; @Repository @RequiredArgsConstructor @@ -20,15 +21,17 @@ public class RoomRepositoryImpl implements RoomRepository { private final UserRepository userRepository; private final PickerRepository pickerRepository; - private final Map node2roomsMap = new ConcurrentHashMap<>(); + private final Map node2roomsMap = new HashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(true); @Override public void create(Room room) throws RoomAlreadyExistException { - var nodeId = room.getNodeId(); + var nodeId = room.getNodeIdentifier(); - synchronized (node2roomsMap) { + lock.writeLock().lock(); + try { var node = node2roomsMap.keySet().stream() - .filter(n -> room.getNodeId().equals(n.id())) + .filter(n -> room.getNodeIdentifier().equals(n.getIdentifier())) .findFirst(); if (node.isEmpty()) { @@ -36,71 +39,83 @@ public void create(Room room) throws RoomAlreadyExistException { } var rooms = node2roomsMap.get(node.get()); - if (rooms.containsKey(room.getId())) { - throw new RoomAlreadyExistException(room.getNodeId(), room.getId()); + if (rooms.containsKey(room.getIdentifier())) { + throw new RoomAlreadyExistException(room.getNodeIdentifier(), room.getIdentifier()); } - rooms.put(room.getId(), new RoomContainer(room, new AtomicInteger(0))); - pickerRepository.find(room.getNodeId()).add(room); + rooms.put(room.getIdentifier(), new RoomContainer(room, new AtomicInteger(0))); + pickerRepository.find(room.getNodeIdentifier()).add(room); + } finally { + lock.writeLock().unlock(); } } @Override public void remove(Room room) { - var nodeId = room.getNodeId(); + var nodeId = room.getNodeIdentifier(); var node = node2roomsMap.keySet().stream() - .filter(n -> room.getNodeId().equals(n.id())) + .filter(n -> room.getNodeIdentifier().equals(n.getIdentifier())) .findFirst(); - synchronized (node2roomsMap) { + lock.writeLock().lock(); + try { if (node.isEmpty()) { throw new NodeNotFoundException("Node '" + nodeId + "' does not exist"); } - node2roomsMap.get(node.get()).remove(room.getId()); - pickerRepository.find(room.getNodeId()).remove(room); - } + node2roomsMap.get(node.get()).remove(room.getIdentifier()); + pickerRepository.find(room.getNodeIdentifier()).remove(room); - userRepository.onRemoveRoom(room); + userRepository.onRemoveRoom(room); + } finally { + lock.writeLock().unlock(); + } } @Override public Optional find(Node node, String identifier) { - synchronized (node2roomsMap) { + lock.readLock().lock(); + try { if (!node2roomsMap.containsKey(node)) { - throw new NodeNotFoundException("Node '" + node.id() + "' does not exist"); + throw new NodeNotFoundException("Node '" + node.getIdentifier() + "' does not exist"); } var result = node2roomsMap.get(node).getOrDefault(identifier, null); return result == null? Optional.empty() : Optional.of(result.room()); + } finally { + lock.readLock().unlock(); } } @Override public List all(Node node) { - synchronized (node2roomsMap) { + lock.readLock().lock(); + try { if (!node2roomsMap.containsKey(node)) { - throw new NodeNotFoundException("Node '%s' does not exists".formatted(node.id())); + throw new NodeNotFoundException("Node '%s' does not exists".formatted(node.getIdentifier())); } return node2roomsMap.get(node).values().stream().map(RoomContainer::room).toList(); + } finally { + lock.readLock().unlock(); } } @Override public Optional pickFree(Node node, Collection users) { - synchronized (node2roomsMap) { + lock.writeLock().lock(); + try { if (!node2roomsMap.containsKey(node)) { - throw new NodeNotFoundException("Node '" + node.id() + "' does not exist"); + throw new NodeNotFoundException("Node '" + node.getIdentifier() + "' does not exist"); } Room room = null; try { - room = pickerRepository.pick(node.id(), users); + room = pickerRepository.pick(node.getIdentifier(), users); } catch (RuntimeException ignore) {} // TODO: may be problem. Check it later Optional container = room == null? Optional.empty() : - Optional.of(node2roomsMap.get(node).get(room.getId())); + Optional.of(node2roomsMap.get(node).get(room.getIdentifier())); if (container.isPresent()) { var cont = container.get(); @@ -109,24 +124,32 @@ public Optional pickFree(Node node, Collection users) { } return container.map(RoomContainer::room); + } finally { + lock.writeLock().unlock(); } } @Override public void onCreateNode(Node node) { - synchronized (node2roomsMap) { + lock.writeLock().lock(); + try { node2roomsMap.put(node, new Rooms()); + } finally { + lock.writeLock().unlock(); } } @Override public List onRemoveNode(Node node) { - List deleted; - synchronized (node2roomsMap) { - deleted = node2roomsMap.get(node).values().stream().map(container -> container.room).toList(); + lock.writeLock().lock(); + try { + var deleted = node2roomsMap.get(node).values().stream().map(container -> container.room).toList(); node2roomsMap.remove(node); + + return deleted; + } finally { + lock.writeLock().unlock(); } - return deleted; } private record RoomContainer(Room room, AtomicInteger used) { diff --git a/server/src/main/java/ru/dragonestia/picker/repository/impl/UserRepositoryImpl.java b/server/src/main/java/ru/dragonestia/picker/repository/impl/UserRepositoryImpl.java index 279b40c..f41adeb 100644 --- a/server/src/main/java/ru/dragonestia/picker/repository/impl/UserRepositoryImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/repository/impl/UserRepositoryImpl.java @@ -10,26 +10,29 @@ import ru.dragonestia.picker.repository.impl.picker.LeastPickedPicker; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; @Repository @RequiredArgsConstructor public class UserRepositoryImpl implements UserRepository { private final NodeId2PickerModeCache nodeId2PickerModeCache; - private final Map> usersMap = new ConcurrentHashMap<>(); - private final Map> roomUsers = new ConcurrentHashMap<>(); + private final Map> usersMap = new HashMap<>(); + private final Map> roomUsers = new HashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(true); @Override public Map linkWithRoom(Room room, Collection users, boolean force) throws RoomAreFullException { var result = new HashMap(); - synchronized (usersMap) { - var path = new NodeRoomPath(room.getNodeId(), room.getId()); + lock.writeLock().lock(); + try { + var path = new NodeRoomPath(room.getNodeIdentifier(), room.getIdentifier()); var usersSet = roomUsers.getOrDefault(path, new HashSet<>()); - if (force || room.getSlots().isUnlimited()) { + if (force || room.hasUnlimitedSlots()) { users.forEach(user -> result.put(user, true)); } else { for (var user : users) { @@ -37,8 +40,8 @@ public Map linkWithRoom(Room room, Collection users, boolea result.put(user, !set.contains(room)); } - if (room.getSlots().getSlots() < usersSet.size() + users.size()) { - throw new RoomAreFullException(room.getNodeId(), room.getId()); + if (room.getMaxSlots() < usersSet.size() + users.size()) { + throw new RoomAreFullException(room.getNodeIdentifier(), room.getIdentifier()); } } @@ -51,10 +54,12 @@ public Map linkWithRoom(Room room, Collection users, boolea usersSet.addAll(users); roomUsers.put(path, usersSet); - var picker = nodeId2PickerModeCache.get(room.getNodeId()); + var picker = nodeId2PickerModeCache.get(room.getNodeIdentifier()); if (picker instanceof LeastPickedPicker leastPickedPicker) { leastPickedPicker.updateUsersAmount(room, roomUsers.get(path).size()); } + } finally { + lock.writeLock().unlock(); } return result; @@ -63,7 +68,9 @@ public Map linkWithRoom(Room room, Collection users, boolea @Override public int unlinkWithRoom(Room room, Collection users) { var counter = new AtomicInteger(); - synchronized (usersMap) { + + lock.writeLock().lock(); + try { usersMap.forEach((user, set) -> { if (!set.contains(room)) return; @@ -75,7 +82,7 @@ public int unlinkWithRoom(Room room, Collection users) { } }); - var path = new NodeRoomPath(room.getNodeId(), room.getId()); + var path = new NodeRoomPath(room.getNodeIdentifier(), room.getIdentifier()); var set = roomUsers.getOrDefault(path, new HashSet<>()); set.removeAll(users); if (set.isEmpty()) { @@ -84,49 +91,63 @@ public int unlinkWithRoom(Room room, Collection users) { roomUsers.put(path, set); } - var picker = nodeId2PickerModeCache.get(room.getNodeId()); + var picker = nodeId2PickerModeCache.get(room.getNodeIdentifier()); if (picker instanceof LeastPickedPicker leastPickedPicker) { leastPickedPicker.updateUsersAmount(room, set.size()); } + } finally { + lock.writeLock().unlock(); } return counter.get(); } @Override public List findAllLinkedUserRooms(User user) { - synchronized (usersMap) { + lock.writeLock().lock(); + try { return usersMap.getOrDefault(user, new HashSet<>()).stream().toList(); + } finally { + lock.writeLock().unlock(); } } @Override public void onRemoveRoom(Room room) { - synchronized (usersMap) { + lock.writeLock().lock(); + try { usersMap.forEach((user, set) -> { set.remove(room); if (set.isEmpty()) { usersMap.remove(user); } }); + } finally { + lock.writeLock().unlock(); } } @Override public List usersOf(Room room) { - synchronized (usersMap) { - return roomUsers.getOrDefault(new NodeRoomPath(room.getNodeId(), room.getId()), new HashSet<>()) + lock.readLock().lock(); + try { + return roomUsers.getOrDefault(new NodeRoomPath(room.getNodeIdentifier(), room.getIdentifier()), new HashSet<>()) .stream() .toList(); + } finally { + lock.readLock().unlock(); } } @Override public List search(String input) { - synchronized (usersMap) { + lock.readLock().lock(); + try { return usersMap.keySet().stream() - .filter(user -> user.id().startsWith(input)) - .sorted(Comparator.comparing(User::id)) + .filter(user -> user.getIdentifier().startsWith(input)) + .sorted(Comparator.comparing(User::getIdentifier)) .toList(); + } finally { + lock.readLock().unlock(); } } 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 cca8b1b..4a81985 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 @@ -27,7 +27,7 @@ public void add(Room room) { @Override public void remove(Room room) { synchronized (map) { - map.removeById(room.getId()); + map.removeById(room.getIdentifier()); } } @@ -50,7 +50,7 @@ public Room pick(Collection users) { public void updateUsersAmount(Room room, int users) { synchronized (map) { - map.updateItem(room.getId(), prevValue -> users); + map.updateItem(room.getIdentifier(), prevValue -> users); } } 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 d58edc4..1d0db9f 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 @@ -20,7 +20,7 @@ public RoomWrapper(Room room, Supplier userCountSupplier) { @Override public String getId() { - return room.getId(); + return room.getIdentifier(); } @Override @@ -30,7 +30,7 @@ public int countUnits() { @Override public int maxUnits() { - return room.getSlots().getSlots(); + return room.getMaxSlots(); } @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 fad91ea..3902619 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 @@ -29,7 +29,7 @@ public void add(Room room) { @Override public void remove(Room room) { synchronized (list) { - list.removeById(room.getId()); + list.removeById(room.getIdentifier()); } } 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 180b12a..9cc221c 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 @@ -21,14 +21,14 @@ public SequentialFillingPicker(UserRepository userRepository) { @Override public void add(Room room) { synchronized (wrappers) { - wrappers.put(room.getId(), new RoomWrapper(room, () -> userRepository.usersOf(room).size())); + wrappers.put(room.getIdentifier(), new RoomWrapper(room, () -> userRepository.usersOf(room).size())); } } @Override public void remove(Room room) { synchronized (wrappers) { - wrappers.remove(room.getId()); + wrappers.remove(room.getIdentifier()); } } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/NodeServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/NodeServiceImpl.java index 88f1888..3ec93ed 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/NodeServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/NodeServiceImpl.java @@ -29,7 +29,7 @@ public class NodeServiceImpl implements NodeService { @Override public void create(Node node) throws InvalidNodeIdentifierException, NodeAlreadyExistException { - namingValidator.validateNodeId(node.id()); + namingValidator.validateNodeId(node.getIdentifier()); nodeRepository.create(node); storage.saveNode(node); } 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 e825c2d..af05a0f 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 @@ -41,11 +41,11 @@ public class RoomServiceImpl implements RoomService { @Override public void create(Room room) throws InvalidRoomIdentifierException, RoomAlreadyExistException, NotPersistedNodeException { - namingValidator.validateRoomId(room.getNodeId(), room.getId()); + namingValidator.validateRoomId(room.getNodeIdentifier(), room.getIdentifier()); - var node = nodeRepository.find(room.getNodeId()).orElseThrow(() -> new NodeNotFoundException(room.getNodeId())); - if (!node.persist() && room.isPersist()) { - throw new NotPersistedNodeException(node.id(), room.getId()); + var node = nodeRepository.find(room.getNodeIdentifier()).orElseThrow(() -> new NodeNotFoundException(room.getNodeIdentifier())); + if (!node.isPersist() && room.isPersist()) { + throw new NotPersistedNodeException(node.getIdentifier(), room.getIdentifier()); } roomRepository.create(room); @@ -84,13 +84,13 @@ public PickedRoomResponse pickAvailable(Node node, List users) { var roomUsers = userRepository.usersOf(room); return new PickedRoomResponse( - room.getNodeId(), - room.getId(), + room.getNodeIdentifier(), + room.getIdentifier(), room.getPayload(), - room.getSlots().getSlots(), + room.getMaxSlots(), roomUsers.size(), room.isLocked(), - roomUsers.stream().map(User::id).collect(Collectors.toSet()) + roomUsers.stream().map(User::getIdentifier).collect(Collectors.toSet()) ); } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/UserServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/UserServiceImpl.java index ad9c1cb..1b68dbe 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/UserServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/UserServiceImpl.java @@ -6,6 +6,7 @@ import ru.dragonestia.picker.api.model.room.ShortResponseRoom; import ru.dragonestia.picker.api.model.user.ResponseUser; import ru.dragonestia.picker.api.model.user.UserDetails; +import ru.dragonestia.picker.api.repository.type.UserIdentifier; import ru.dragonestia.picker.model.Room; import ru.dragonestia.picker.model.User; import ru.dragonestia.picker.repository.UserRepository; @@ -67,6 +68,6 @@ public List searchUsers(String input, Set details) { @Override public ResponseUser getUserDetails(String userId, Set details) { - return detailsExtractor.extract(new User(userId), details); + return detailsExtractor.extract(new User(UserIdentifier.of(userId)), details); } } 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 529708c..dbb8f1e 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 @@ -65,8 +65,8 @@ public void loadAll() { @Override public void saveNode(Node node) { - if (!node.persist()) return; - var nodeFile = new File(path + "/nodes/" + node.id() + ".json"); + if (!node.isPersist()) return; + var nodeFile = new File(path + "/nodes/" + node.getIdentifier() + ".json"); var writer = objectMapper.writer(); try { @@ -78,17 +78,17 @@ public void saveNode(Node node) { @Override public void removeNode(Node node) { - if (!node.persist()) return; - new File(path + "/nodes/" + node.id() + ".json").delete(); + if (!node.isPersist()) return; + new File(path + "/nodes/" + node.getIdentifier() + ".json").delete(); - log.info("Removed node '%s' from disk storage".formatted(node.id())); + log.info("Removed node '%s' from disk storage".formatted(node.getIdentifier())); } @SneakyThrows @Override public void saveRoom(Room room) { if (!room.isPersist()) return; - var roomFile = new File(path + "/rooms/" + room.getNodeId() + "." + room.getId() + ".json"); + var roomFile = new File("%s/rooms/%s.%s.json".formatted(path, room.getNodeIdentifier(), room.getIdentifier())); var writer = objectMapper.writer(); try { @@ -101,8 +101,8 @@ public void saveRoom(Room room) { @Override public void removeRoom(Room room) { if (!room.isPersist()) return; - new File(path + "/rooms/" + room.getNodeId() + "." + room.getId() + ".json").delete(); + new File("%s/rooms/%s.%s.json".formatted(path, room.getNodeIdentifier(), room.getIdentifier())).delete(); - log.info("Removed room '%s/%s' from disk storage".formatted(room.getNodeId(), room.getId())); + log.info("Removed room '%s/%s' from disk storage".formatted(room.getNodeIdentifier(), room.getIdentifier())); } } diff --git a/server/src/main/java/ru/dragonestia/picker/util/DetailsExtractor.java b/server/src/main/java/ru/dragonestia/picker/util/DetailsExtractor.java index 7bad143..8afe83a 100644 --- a/server/src/main/java/ru/dragonestia/picker/util/DetailsExtractor.java +++ b/server/src/main/java/ru/dragonestia/picker/util/DetailsExtractor.java @@ -30,7 +30,7 @@ public ResponseNode extract(Node node, Set details) { for (var detail: details) { if (detail == NodeDetails.PERSIST) { - response.putDetail(NodeDetails.PERSIST, Boolean.toString(node.persist())); + response.putDetail(NodeDetails.PERSIST, Boolean.toString(node.isPersist())); continue; } } diff --git a/server/src/main/java/ru/dragonestia/picker/util/NamingValidator.java b/server/src/main/java/ru/dragonestia/picker/util/NamingValidator.java index 9ed1238..d49c263 100644 --- a/server/src/main/java/ru/dragonestia/picker/util/NamingValidator.java +++ b/server/src/main/java/ru/dragonestia/picker/util/NamingValidator.java @@ -4,6 +4,7 @@ import ru.dragonestia.picker.api.exception.InvalidNodeIdentifierException; import ru.dragonestia.picker.api.exception.InvalidRoomIdentifierException; import ru.dragonestia.picker.api.exception.InvalidUsernamesException; +import ru.dragonestia.picker.api.repository.type.UserIdentifier; import ru.dragonestia.picker.api.util.IdentifierValidator; import ru.dragonestia.picker.model.User; @@ -35,7 +36,7 @@ public List validateUserIds(List input) throws InvalidUsernamesExc for (var username: input) { if (validateUserId(username)) { - users.add(new User(username)); + users.add(new User(UserIdentifier.of(username))); continue; } 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 0205d17..07faf52 100644 --- a/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java +++ b/server/src/test/java/ru/dragonestia/picker/config/FillingNodesConfig.java @@ -4,10 +4,12 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import ru.dragonestia.picker.api.model.node.PickingMethod; +import ru.dragonestia.picker.api.repository.type.NodeIdentifier; +import ru.dragonestia.picker.api.repository.type.RoomIdentifier; +import ru.dragonestia.picker.api.repository.type.UserIdentifier; import ru.dragonestia.picker.model.Node; import ru.dragonestia.picker.model.Room; import ru.dragonestia.picker.model.User; -import ru.dragonestia.picker.model.type.SlotLimit; import ru.dragonestia.picker.repository.NodeRepository; import ru.dragonestia.picker.repository.RoomRepository; import ru.dragonestia.picker.repository.UserRepository; @@ -51,7 +53,7 @@ public class FillingNodesConfig { @Bean void createSequentialFillingNode() { - var node = new Node("seq", PickingMethod.SEQUENTIAL_FILLING, false); + var node = new Node(NodeIdentifier.of("seq"), PickingMethod.SEQUENTIAL_FILLING, false); nodeRepository.create(node); fillNode(node); @@ -61,7 +63,7 @@ void createSequentialFillingNode() { @Bean void createRoundRobinNode() { - var node = new Node("round", PickingMethod.ROUND_ROBIN, false); + var node = new Node(NodeIdentifier.of("round"), PickingMethod.ROUND_ROBIN, false); nodeRepository.create(node); fillNode(node); @@ -71,7 +73,7 @@ void createRoundRobinNode() { @Bean void createLeastPickerNode() { - var node = new Node("least", PickingMethod.LEAST_PICKED, false); + var node = new Node(NodeIdentifier.of("least"), PickingMethod.LEAST_PICKED, false); nodeRepository.create(node); fillNode(node); @@ -83,12 +85,12 @@ private void fillNode(Node node) { for (int i = 0, n = 5; i < n; i++) { for (int j = 0; j < 3; j++) { var roomId = "room-" + i + "-" + j; - var room = Room.create(roomId, node, SlotLimit.of(n), "", false); + var room = new Room(RoomIdentifier.of(roomId), node, n, "", false); roomRepository.create(room); var users = n - i; for (int k = users - 1; k >= 0; k--) { - var user = new User("user-" + k); + var user = new User(UserIdentifier.of("user-" + k)); userRepository.linkWithRoom(room, List.of(user), false); } 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 7e41230..b8df440 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/LeastPickedTests.java @@ -44,11 +44,11 @@ void testPicking(String expectedRoomId, int usersAmount) { Assertions.assertTrue(roomOpt.isPresent()); var room = roomOpt.get(); - var slots = room.getSlots(); + var slots = room.getMaxSlots(); var users = userRepository.usersOf(room); - Assertions.assertTrue(slots.isUnlimited() || slots.getSlots() >= users.size()); // check slots limitation + Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - Assertions.assertEquals(expectedRoomId, room.getId()); + Assertions.assertEquals(expectedRoomId, room.getIdentifier()); } 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 82ec768..ec23f94 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/RoundRobinTests.java @@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; +import ru.dragonestia.picker.api.model.node.INode; import ru.dragonestia.picker.config.FillingNodesConfig; import ru.dragonestia.picker.model.Node; import ru.dragonestia.picker.repository.RoomRepository; @@ -42,11 +43,11 @@ void testPicking(String expectedRoomId, int usersAmount) { Assertions.assertTrue(roomOpt.isPresent()); var room = roomOpt.get(); - var slots = room.getSlots(); + var slots = room.getMaxSlots(); var users = userRepository.usersOf(room); - Assertions.assertTrue(slots.isUnlimited() || slots.getSlots() >= users.size()); // check slots limitation + Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - Assertions.assertEquals(expectedRoomId, room.getId()); + Assertions.assertEquals(expectedRoomId, room.getIdentifier()); } 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 50e6673..61fb5c8 100644 --- a/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java +++ b/server/src/test/java/ru/dragonestia/picker/picker/SequentialFillingTests.java @@ -44,11 +44,11 @@ void testPicking(String expectedRoomId, int usersAmount) { Assertions.assertTrue(roomOpt.isPresent()); var room = roomOpt.get(); - var slots = room.getSlots(); + var slots = room.getMaxSlots(); var users = userRepository.usersOf(room); - Assertions.assertTrue(slots.isUnlimited() || slots.getSlots() >= users.size()); // check slots limitation + Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation - Assertions.assertEquals(expectedRoomId, room.getId()); + Assertions.assertEquals(expectedRoomId, room.getIdentifier()); } public static class PickingArgumentProvider implements ArgumentsProvider { diff --git a/server/src/test/java/ru/dragonestia/picker/service/NodeServiceTests.java b/server/src/test/java/ru/dragonestia/picker/service/NodeServiceTests.java index fceed8b..1dff9fd 100644 --- a/server/src/test/java/ru/dragonestia/picker/service/NodeServiceTests.java +++ b/server/src/test/java/ru/dragonestia/picker/service/NodeServiceTests.java @@ -6,6 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest; import ru.dragonestia.picker.api.exception.NodeAlreadyExistException; import ru.dragonestia.picker.api.model.node.PickingMethod; +import ru.dragonestia.picker.api.repository.type.NodeIdentifier; import ru.dragonestia.picker.model.Node; import java.util.List; @@ -18,15 +19,15 @@ public class NodeServiceTests { @Test void test_nodeCreateAndRemove() { - var node = new Node("test", PickingMethod.SEQUENTIAL_FILLING, false); + var node = new Node(NodeIdentifier.of("test"), PickingMethod.SEQUENTIAL_FILLING, false); Assertions.assertDoesNotThrow(() -> nodeService.create(node)); - Assertions.assertTrue(nodeService.find(node.id()).isPresent()); + Assertions.assertTrue(nodeService.find(node.getIdentifier()).isPresent()); Assertions.assertThrows(NodeAlreadyExistException.class, () -> nodeService.create(node)); nodeService.remove(node); - Assertions.assertFalse(() -> nodeService.find(node.id()).isPresent()); + Assertions.assertFalse(() -> nodeService.find(node.getIdentifier()).isPresent()); } @Test @@ -34,9 +35,9 @@ void test_allNodes() { nodeService.all().forEach(node -> nodeService.remove(node)); var nodes = List.of( - new Node("test1", PickingMethod.SEQUENTIAL_FILLING, false), - new Node("test2", PickingMethod.ROUND_ROBIN, false), - new Node("test3", PickingMethod.ROUND_ROBIN, false) + new Node(NodeIdentifier.of("test1"), PickingMethod.SEQUENTIAL_FILLING, false), + new Node(NodeIdentifier.of("test2"), PickingMethod.ROUND_ROBIN, false), + new Node(NodeIdentifier.of("test3"), PickingMethod.ROUND_ROBIN, false) ); nodes.forEach(node -> nodeService.create(node)); 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 75f8f3a..80b9ad3 100644 --- a/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java +++ b/server/src/test/java/ru/dragonestia/picker/service/RoomServiceTests.java @@ -10,6 +10,10 @@ import ru.dragonestia.picker.api.exception.NotPersistedNodeException; import ru.dragonestia.picker.api.exception.RoomAlreadyExistException; 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.UserIdentifier; import ru.dragonestia.picker.model.Node; import ru.dragonestia.picker.model.Room; import ru.dragonestia.picker.model.User; @@ -30,7 +34,7 @@ public class RoomServiceTests { @BeforeEach void init() { - node = new Node("test-rooms", PickingMethod.SEQUENTIAL_FILLING, false); + node = new Node(NodeIdentifier.of("test-rooms"), PickingMethod.SEQUENTIAL_FILLING, false); try { nodeService.create(node); @@ -39,24 +43,24 @@ void init() { @Test void test_createAndRemove() { - var room = Room.create("test-room", node, SlotLimit.unlimited(), "", false); + var room = new Room(RoomIdentifier.of("test-room"), node, IRoom.UNLIMITED_SLOTS, "", false); roomService.create(room); - Assertions.assertTrue(roomService.find(node, room.getId()).isPresent()); + Assertions.assertTrue(roomService.find(node, room.getIdentifier()).isPresent()); Assertions.assertThrows(RoomAlreadyExistException.class, () -> roomService.create(room)); roomService.remove(room); - Assertions.assertFalse(roomService.find(node, room.getId()).isPresent()); + Assertions.assertFalse(roomService.find(node, room.getIdentifier()).isPresent()); } @Test void test_allRooms() { var rooms = List.of( - Room.create("test-room1", node, SlotLimit.of(1), "", false), - Room.create("test-room2", node, SlotLimit.of(2), "", false), - Room.create("test-room3", node, SlotLimit.of(3), "", false), - Room.create("test-room4", node, SlotLimit.unlimited(), "", false) + new Room(RoomIdentifier.of("test-room1"), node, 1, "", false), + new Room(RoomIdentifier.of("test-room2"), node, 2, "", false), + new Room(RoomIdentifier.of("test-room3"), node, 3, "", false), + new Room(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false) ); rooms.forEach(room -> roomService.create(room)); @@ -69,27 +73,29 @@ void test_allRooms() { @Test void test_exceptNotPersistedNode() { - Assertions.assertThrows(NotPersistedNodeException.class, () -> roomService.create(Room.create("1", node, SlotLimit.unlimited(), "", true))); + Assertions.assertThrows(NotPersistedNodeException.class, () -> { + roomService.create(new Room(RoomIdentifier.of("1"), node, IRoom.UNLIMITED_SLOTS, "", true)); + }); } @Test void test_pickRoom() { var rooms = List.of( - Room.create("test-room1", node, SlotLimit.of(1), "", false), - Room.create("test-room2", node, SlotLimit.of(2), "", false), - Room.create("test-room3", node, SlotLimit.of(3), "", false), - Room.create("test-room4", node, SlotLimit.unlimited(), "", false) + new Room(RoomIdentifier.of("test-room1"), node, 1, "", false), + new Room(RoomIdentifier.of("test-room2"), node, 2, "", false), + new Room(RoomIdentifier.of("test-room3"), node, 3, "", false), + new Room(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false) ); rooms.forEach(room -> roomService.create(room)); var users = List.of( - new User("1"), - new User("2"), - new User("3"), - new User("4"), - new User("5"), - new User("6") + new User(UserIdentifier.of("1")), + new User(UserIdentifier.of("2")), + new User(UserIdentifier.of("3")), + new User(UserIdentifier.of("4")), + new User(UserIdentifier.of("5")), + new User(UserIdentifier.of("6")) ); @@ -105,12 +111,12 @@ void test_removeNode() { @Test void test_nodeDoesNotExists() { - var node = new Node("Bruh", PickingMethod.ROUND_ROBIN, false); - var room = Room.create("test", node, SlotLimit.unlimited(), "", false); + var node = new Node(NodeIdentifier.of("bruh"), PickingMethod.ROUND_ROBIN, false); + var room = new Room(RoomIdentifier.of("test"), node, IRoom.UNLIMITED_SLOTS, "", false); Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.create(room)); Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.remove(room)); Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.find(node, "Bruh")); - Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.pickAvailable(node, List.of(new User("1")))); + Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.pickAvailable(node, List.of(new User(UserIdentifier.of("1"))))); } } diff --git a/server/src/test/java/ru/dragonestia/picker/util/UserFiller.java b/server/src/test/java/ru/dragonestia/picker/util/UserFiller.java index 4f18c90..0c17815 100644 --- a/server/src/test/java/ru/dragonestia/picker/util/UserFiller.java +++ b/server/src/test/java/ru/dragonestia/picker/util/UserFiller.java @@ -1,6 +1,7 @@ package ru.dragonestia.picker.util; import org.springframework.boot.test.context.TestComponent; +import ru.dragonestia.picker.api.repository.type.UserIdentifier; import ru.dragonestia.picker.model.User; import java.util.LinkedList; @@ -13,7 +14,7 @@ public class UserFiller { public List createRandomUsers(int amount) { var list = new LinkedList(); for (int i = 0; i < amount; i++) { - list.add(new User(UUID.randomUUID().toString())); + list.add(new User(UserIdentifier.of(UUID.randomUUID().toString()))); } return list; }