!renamed User to Entity

This commit is contained in:
Andrey Terentev 2024-05-10 22:06:15 +07:00 committed by Andrey Terentev
parent cdb4f69a0f
commit b4b0cf2a64
71 changed files with 483 additions and 538 deletions

View File

@ -22,7 +22,7 @@ After that, you can connect to the server using `RoomPicker Client`.
Example of using the RoomPicker Client
----------
Create a Node and a Room, after that, system pick up a room for 5 users.
Create a Node and a Room, after that, system pick up a room for 5 entities.
```java
class Example {
public static void main(String[] args) {
@ -45,14 +45,14 @@ class Example {
.setPayload("Hello world!");
client.getRoomRepository().saveRoom(roomDefinition);
// Picking room for 5 users
var users = new HashSet<UserIdentifier>();
// Picking room for 5 entities
var entities = new HashSet<UserIdentifier>();
for (int i = 0 ; i < 5; i++) {
var user = UserIdentifier.of("test-user-" + i);
users.add(user);
var entity = UserIdentifier.of("test-entity-" + i);
entities.add(entity);
}
try {
var response = client.getNodeRepository().pickRoom(nodeId, users);
var response = client.getNodeRepository().pickRoom(nodeId, entities);
// TODO...
} catch (NoRoomsAvailableException ex) {
// Cannot pick room

View File

@ -18,8 +18,8 @@ public class ExceptionFactory {
factory.put(InvalidInstanceIdentifierException.ERROR_ID, InvalidInstanceIdentifierException::new);
factory.put(InvalidRoomIdentifierException.ERROR_ID, InvalidRoomIdentifierException::new);
factory.put(InvalidUsernamesException.ERROR_ID, InvalidUsernamesException::new);
factory.put(NodeAlreadyExistException.ERROR_ID, NodeAlreadyExistException::new);
factory.put(NodeNotFoundException.ERROR_ID, NodeNotFoundException::new);
factory.put(InstanceAlreadyExistException.ERROR_ID, InstanceAlreadyExistException::new);
factory.put(InstanceNotFoundException.ERROR_ID, InstanceNotFoundException::new);
factory.put(NoRoomsAvailableException.ERROR_ID, NoRoomsAvailableException::new);
factory.put(RoomAlreadyExistException.ERROR_ID, RoomAlreadyExistException::new);
factory.put(RoomAreFullException.ERROR_ID, RoomAreFullException::new);

View File

@ -4,17 +4,17 @@ import ru.dragonestia.picker.api.repository.response.ErrorResponse;
import java.util.Map;
public final class NodeAlreadyExistException extends ApiException {
public final class InstanceAlreadyExistException extends ApiException {
public static final String ERROR_ID = "err.node.already_exists";
private final String nodeId;
public NodeAlreadyExistException(String nodeId) {
public InstanceAlreadyExistException(String nodeId) {
this.nodeId = nodeId;
}
public NodeAlreadyExistException(ErrorResponse errorResponse) {
public InstanceAlreadyExistException(ErrorResponse errorResponse) {
this(errorResponse.details().get("nodeId"));
}

View File

@ -4,23 +4,23 @@ import ru.dragonestia.picker.api.repository.response.ErrorResponse;
import java.util.Map;
public final class NodeNotFoundException extends ApiException {
public final class InstanceNotFoundException extends ApiException {
public static final String ERROR_ID = "err.node.not_found";
public static final String ERROR_ID = "err.instance.not_found";
private final String nodeId;
public NodeNotFoundException(String nodeId) {
public InstanceNotFoundException(String nodeId) {
this.nodeId = nodeId;
}
public NodeNotFoundException(ErrorResponse errorResponse) {
this(errorResponse.details().get("node"));
public InstanceNotFoundException(ErrorResponse errorResponse) {
this(errorResponse.details().get("instance"));
}
@Override
public String getMessage() {
return "Node '" + nodeId + "' does not found";
return "Instance '" + nodeId + "' does not found";
}
public String getNodeId() {
@ -34,6 +34,6 @@ public final class NodeNotFoundException extends ApiException {
@Override
public void appendDetailsToErrorResponse(Map<String, String> details) {
details.put("node", getNodeId());
details.put("instance", getNodeId());
}
}

View File

@ -2,7 +2,7 @@ package ru.dragonestia.picker.api.model.user;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.beans.Transient;
@ -11,8 +11,8 @@ public interface IUser {
@NotNull String getIdentifier();
@Transient
default @NotNull UserIdentifier getIdentifierObject() {
return UserIdentifier.of(getIdentifier());
default @NotNull EntityIdentifier getIdentifierObject() {
return EntityIdentifier.of(getIdentifier());
}
@Nullable String getDetail(@NotNull UserDetails detail);

View File

@ -2,13 +2,13 @@ package ru.dragonestia.picker.api.model.user;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
public class UserDefinition implements IUser {
private final String id;
public UserDefinition(@NotNull UserIdentifier identifier) {
public UserDefinition(@NotNull EntityIdentifier identifier) {
id = identifier.getValue();
}

View File

@ -8,7 +8,7 @@ import ru.dragonestia.picker.api.repository.query.node.GetAllNodes;
import ru.dragonestia.picker.api.repository.query.node.RemoveNodesByIds;
import ru.dragonestia.picker.api.repository.response.PickedRoomResponse;
import ru.dragonestia.picker.api.repository.type.NodeIdentifier;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.List;
import java.util.Optional;
@ -26,5 +26,5 @@ public interface NodeRepository {
void saveNode(@NotNull NodeDefinition definition);
@NotNull PickedRoomResponse pickRoom(@NotNull NodeIdentifier identifier, @NotNull Set<UserIdentifier> users);
@NotNull PickedRoomResponse pickRoom(@NotNull NodeIdentifier identifier, @NotNull Set<EntityIdentifier> users);
}

View File

@ -3,7 +3,7 @@ package ru.dragonestia.picker.api.repository.query.user;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.model.room.RoomDetails;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.Arrays;
import java.util.HashSet;
@ -29,14 +29,14 @@ public class FindRoomsLinkedWithUser {
}
@Contract("_ -> new")
public static @NotNull FindRoomsLinkedWithUser just(@NotNull UserIdentifier identifier) {
public static @NotNull FindRoomsLinkedWithUser just(@NotNull EntityIdentifier identifier) {
return FindRoomsLinkedWithUser.builder()
.setUserId(identifier)
.build();
}
@Contract("_ -> new")
public static @NotNull FindRoomsLinkedWithUser withAllDetails(@NotNull UserIdentifier identifier) {
public static @NotNull FindRoomsLinkedWithUser withAllDetails(@NotNull EntityIdentifier identifier) {
return FindRoomsLinkedWithUser.builder()
.setUserId(identifier)
.setDetails(Arrays.stream(RoomDetails.values()).collect(Collectors.toSet()))
@ -55,7 +55,7 @@ public class FindRoomsLinkedWithUser {
private Builder() {}
@Contract("_ -> this")
public @NotNull Builder setUserId(@NotNull UserIdentifier identifier) {
public @NotNull Builder setUserId(@NotNull EntityIdentifier identifier) {
userId = identifier.getValue();
return this;
}

View File

@ -3,7 +3,7 @@ package ru.dragonestia.picker.api.repository.query.user;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.model.user.UserDetails;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.*;
import java.util.stream.Collectors;
@ -27,14 +27,14 @@ public class FindUserById {
}
@Contract("_ -> new")
public static @NotNull FindUserById just(@NotNull UserIdentifier userId) {
public static @NotNull FindUserById just(@NotNull EntityIdentifier userId) {
return builder()
.setUserId(userId)
.build();
}
@Contract("_ -> new")
public static @NotNull FindUserById withAllDetails(@NotNull UserIdentifier userId) {
public static @NotNull FindUserById withAllDetails(@NotNull EntityIdentifier userId) {
return builder()
.setUserId(userId)
.setDetails(Arrays.stream(UserDetails.values()).collect(Collectors.toSet()))
@ -53,7 +53,7 @@ public class FindUserById {
private Builder() {}
@Contract("_ -> this")
public @NotNull Builder setUserId(@NotNull UserIdentifier identifier) {
public @NotNull Builder setUserId(@NotNull EntityIdentifier identifier) {
userId = identifier.getValue();
return this;
}

View File

@ -4,7 +4,7 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
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.api.repository.type.EntityIdentifier;
import java.util.HashSet;
import java.util.Set;
@ -48,7 +48,7 @@ public class LinkUsersWithRoom {
private String nodeId = null;
private String roomId = null;
private Set<UserIdentifier> users = new HashSet<>();
private Set<EntityIdentifier> users = new HashSet<>();
private boolean ignoreSlotLimitation = false;
private Builder() {}
@ -66,13 +66,13 @@ public class LinkUsersWithRoom {
}
@Contract("_ -> this")
public @NotNull Builder setUsers(@NotNull Set<UserIdentifier> users) {
public @NotNull Builder setUsers(@NotNull Set<EntityIdentifier> users) {
this.users = users;
return this;
}
@Contract("_ -> this")
public @NotNull Builder appendUser(@NotNull UserIdentifier user) {
public @NotNull Builder appendUser(@NotNull EntityIdentifier user) {
users.add(user);
return this;
}

View File

@ -3,7 +3,7 @@ package ru.dragonestia.picker.api.repository.query.user;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.model.user.UserDetails;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.Arrays;
import java.util.Collections;
@ -30,14 +30,14 @@ public class SearchUsers {
}
@Contract("_ -> new")
public static @NotNull SearchUsers just(@NotNull UserIdentifier searchInput) {
public static @NotNull SearchUsers just(@NotNull EntityIdentifier searchInput) {
return SearchUsers.builder()
.setSearchInput(searchInput)
.build();
}
@Contract("_ -> new")
public static @NotNull SearchUsers withAllDetails(@NotNull UserIdentifier searchInput) {
public static @NotNull SearchUsers withAllDetails(@NotNull EntityIdentifier searchInput) {
return SearchUsers.builder()
.setSearchInput(searchInput)
.setDetails(Arrays.stream(UserDetails.values()).collect(Collectors.toSet()))
@ -56,7 +56,7 @@ public class SearchUsers {
private Builder() {}
@Contract("_ -> this")
public @NotNull Builder setSearchInput(@NotNull UserIdentifier input) {
public @NotNull Builder setSearchInput(@NotNull EntityIdentifier input) {
searchInput = input.getValue();
return this;
}

View File

@ -4,7 +4,7 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
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.api.repository.type.EntityIdentifier;
import java.util.HashSet;
import java.util.Set;
@ -42,7 +42,7 @@ public class UnlinkUsersFromRoom {
private String nodeId = null;
private String roomId = null;
private Set<UserIdentifier> users = new HashSet<>();
private Set<EntityIdentifier> users = new HashSet<>();
private Builder() {}
@ -59,13 +59,13 @@ public class UnlinkUsersFromRoom {
}
@Contract("_ -> this")
public @NotNull Builder setUsers(@NotNull Set<UserIdentifier> users) {
public @NotNull Builder setUsers(@NotNull Set<EntityIdentifier> users) {
this.users = users;
return this;
}
@Contract("_ -> this")
public @NotNull Builder appendUser(@NotNull UserIdentifier user) {
public @NotNull Builder appendUser(@NotNull EntityIdentifier user) {
users.add(user);
return this;
}

View File

@ -5,9 +5,9 @@ import ru.dragonestia.picker.api.util.IdentifierValidator;
import java.security.InvalidParameterException;
public class UserIdentifier extends ValueObject<String> {
public class EntityIdentifier extends ValueObject<String> {
private UserIdentifier(String value) {
private EntityIdentifier(String value) {
super(value);
}
@ -18,7 +18,7 @@ public class UserIdentifier extends ValueObject<String> {
throw new InvalidParameterException("Invalid user identifier");
}
public static @NotNull UserIdentifier of(@NotNull String identifier) {
return new UserIdentifier(identifier);
public static @NotNull EntityIdentifier of(@NotNull String identifier) {
return new EntityIdentifier(identifier);
}
}

View File

@ -2,7 +2,7 @@ package ru.dragonestia.picker.api.impl.repository;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
import ru.dragonestia.picker.api.exception.InstanceNotFoundException;
import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.impl.util.EnumUtils;
import ru.dragonestia.picker.api.impl.util.RestTemplate;
@ -17,7 +17,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.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.List;
import java.util.Optional;
@ -46,7 +46,7 @@ public class NodeRepositoryImpl implements NodeRepository {
params.put("requiredDetails", EnumUtils.enumSetToString(data.getDetails()));
});
return Optional.of(response.node());
} catch (NodeNotFoundException ex) {
} catch (InstanceNotFoundException ex) {
return Optional.empty();
}
}
@ -75,7 +75,7 @@ public class NodeRepositoryImpl implements NodeRepository {
}
@Override
public @NotNull PickedRoomResponse pickRoom(@NotNull NodeIdentifier identifier, @NotNull Set<UserIdentifier> users) {
public @NotNull PickedRoomResponse pickRoom(@NotNull NodeIdentifier identifier, @NotNull Set<EntityIdentifier> users) {
return rest.queryPostWithBody(
"/nodes/" + identifier.getValue() + "/pick",
PickedRoomResponse.class,

View File

@ -15,7 +15,7 @@ import lombok.Getter;
import ru.dragonestia.picker.api.model.room.IRoom;
import ru.dragonestia.picker.api.model.user.IUser;
import ru.dragonestia.picker.api.model.user.UserDefinition;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import java.util.Collection;
import java.util.List;
@ -56,7 +56,7 @@ public class AddUsers extends Details {
.map(user -> user.getUserIdentifierField().getValue())
.map(String::trim)
.filter(user -> !user.isEmpty())
.map(id -> (IUser) new UserDefinition(UserIdentifier.of(id)))
.map(id -> (IUser) new UserDefinition(EntityIdentifier.of(id)))
.toList();
}

View File

@ -48,8 +48,8 @@ public class SecurityConfig extends VaadinWebSecurity {
super.configure(http);
http.formLogin(login -> {
login.successForwardUrl("/nodes");
login.defaultSuccessUrl("/nodes");
login.successForwardUrl("/instances");
login.defaultSuccessUrl("/instances");
});
setLoginView(http, LoginPage.class);
}

View File

@ -24,7 +24,7 @@ import ru.dragonestia.picker.cp.util.RouteParamsExtractor;
@RequiredArgsConstructor
@RolesAllowed("USER")
@PageTitle("Rooms")
@Route(value = "/nodes/:nodeId", layout = MainLayout.class)
@Route(value = "/instances/:nodeId", layout = MainLayout.class)
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {
private final SecurityService securityService;

View File

@ -17,7 +17,7 @@ import ru.dragonestia.picker.cp.service.SecurityService;
@RolesAllowed("USER")
@PageTitle("Nodes")
@RouteAlias(value = "/", layout = MainLayout.class)
@Route(value = "/nodes", layout = MainLayout.class)
@Route(value = "/instances", layout = MainLayout.class)
public class NodesPage extends VerticalLayout {
private final NodeRepository nodeRepository;

View File

@ -36,7 +36,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
@RolesAllowed("USER")
@PageTitle("Room details")
@Route(value = "/nodes/:nodeId/rooms/:roomId", layout = MainLayout.class)
@Route(value = "/instances/:nodeId/rooms/:roomId", layout = MainLayout.class)
public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserver {
private final SecurityService securityService;

View File

@ -19,7 +19,7 @@ import ru.dragonestia.picker.api.model.user.IUser;
import ru.dragonestia.picker.api.model.user.UserDetails;
import ru.dragonestia.picker.api.repository.UserRepository;
import ru.dragonestia.picker.api.repository.query.user.SearchUsers;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import ru.dragonestia.picker.cp.component.RefreshableTable;
import ru.dragonestia.picker.cp.service.SecurityService;
@ -98,7 +98,7 @@ public class UserSearchPage extends VerticalLayout implements RefreshableTable {
userGrid.setItems();
}
userGrid.setItems(cachedUsers = userRepository.searchUsers(SearchUsers.withAllDetails(UserIdentifier.of(input)))
userGrid.setItems(cachedUsers = userRepository.searchUsers(SearchUsers.withAllDetails(EntityIdentifier.of(input)))
.stream().map(user -> (IUser) user).toList());
}

View File

@ -4,13 +4,13 @@ import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.ErrorParameter;
import com.vaadin.flow.router.HasErrorParameter;
import jakarta.servlet.http.HttpServletResponse;
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
import ru.dragonestia.picker.api.exception.InstanceNotFoundException;
import ru.dragonestia.picker.cp.component.NavPath;
public class NodeNotFoundPlug extends ErrorPlug implements HasErrorParameter<NodeNotFoundException> {
public class NodeNotFoundPlug extends ErrorPlug implements HasErrorParameter<InstanceNotFoundException> {
@Override
public int setErrorParameter(BeforeEnterEvent beforeEnterEvent, ErrorParameter<NodeNotFoundException> errorParameter) {
public int setErrorParameter(BeforeEnterEvent beforeEnterEvent, ErrorParameter<InstanceNotFoundException> errorParameter) {
var ex = errorParameter.getException();
var nodeId = ex.getNodeId();

View File

@ -3,7 +3,7 @@ package ru.dragonestia.picker.cp.util;
import com.vaadin.flow.router.BeforeEnterEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
import ru.dragonestia.picker.api.exception.InstanceNotFoundException;
import ru.dragonestia.picker.api.exception.RoomNotFoundException;
import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.model.account.IAccount;
@ -15,7 +15,7 @@ import ru.dragonestia.picker.api.repository.query.room.FindRoomById;
import ru.dragonestia.picker.api.repository.query.user.FindUserById;
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.api.repository.type.EntityIdentifier;
@Component
@RequiredArgsConstructor
@ -23,19 +23,19 @@ public class RouteParamsExtractor {
private final RoomPickerClient client;
public INode extractNode(BeforeEnterEvent e) throws NodeNotFoundException {
var nodeId = NodeIdentifier.of(e.getRouteParameters().get("nodeId").orElseThrow(() -> new NodeNotFoundException("null")));
return client.getNodeRepository().findNodeById(FindNodeById.justFind(nodeId)).orElseThrow(() -> new NodeNotFoundException(nodeId.getValue()));
public INode extractNode(BeforeEnterEvent e) throws InstanceNotFoundException {
var nodeId = NodeIdentifier.of(e.getRouteParameters().get("nodeId").orElseThrow(() -> new InstanceNotFoundException("null")));
return client.getNodeRepository().findNodeById(FindNodeById.justFind(nodeId)).orElseThrow(() -> new InstanceNotFoundException(nodeId.getValue()));
}
public IRoom extractRoom(BeforeEnterEvent e, INode node) throws RoomNotFoundException {
var nodeId = node.getIdentifierObject();
var roomId = RoomIdentifier.of(e.getRouteParameters().get("roomId").orElseThrow(() -> new NodeNotFoundException("null")));
return client.getRoomRepository().find(FindRoomById.just(nodeId, roomId)).orElseThrow(() -> new NodeNotFoundException(roomId.getValue()));
var roomId = RoomIdentifier.of(e.getRouteParameters().get("roomId").orElseThrow(() -> new InstanceNotFoundException("null")));
return client.getRoomRepository().find(FindRoomById.just(nodeId, roomId)).orElseThrow(() -> new InstanceNotFoundException(roomId.getValue()));
}
public IUser extractUser(BeforeEnterEvent e) {
var userId = UserIdentifier.of(e.getRouteParameters().get("userId").orElseThrow(RuntimeException::new));
var userId = EntityIdentifier.of(e.getRouteParameters().get("userId").orElseThrow(RuntimeException::new));
return client.getUserRepository().findUserById(FindUserById.withAllDetails(userId));
}

View File

@ -8,7 +8,7 @@ import ru.dragonestia.picker.api.repository.query.node.GetAllNodes;
import ru.dragonestia.picker.api.repository.query.user.UnlinkUsersFromRoom;
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.api.repository.type.EntityIdentifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -76,13 +76,13 @@ public class Main {
try {
synchronized (usersInNode) {
var users = new HashSet<UserIdentifier>();
var users = new HashSet<EntityIdentifier>();
var maxAdd = Math.min(10, (expectedUsers / nodes.size()) - usersInNode.get());
if (maxAdd == 0) return;
var add = maxAdd == 1 ? 1 : (random.nextInt(maxAdd - 1) + 1);
for (int i = 0; i < add; i++) {
users.add(UserIdentifier.of(UUID.randomUUID().toString()));
users.add(EntityIdentifier.of(UUID.randomUUID().toString()));
}
var request = client.getNodeRepository().pickRoom(nodeId, users);

View File

@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.repository.impl.ContainerRepository;
import java.util.Map;
@ -30,7 +30,7 @@ public class UserMetricsAspect {
private final ContainerRepository containerRepository;
private final RoomRepository roomRepository;
private final UserRepository userRepository;
private final EntityRepository entityRepository;
private final MeterRegistry meterRegistry;
private final AtomicInteger totalUsers = new AtomicInteger(0);
@ -41,18 +41,18 @@ public class UserMetricsAspect {
meterRegistry.gauge("roompicker_total_users", totalUsers);
}
@After(value = "execution(* ru.dragonestia.picker.repository.UserRepository.linkWithRoom(ru.dragonestia.picker.model.room.Room, ..)) && args(room, ..)", argNames = "room")
@After(value = "execution(* ru.dragonestia.picker.repository.EntityRepository.linkWithRoom(ru.dragonestia.picker.model.room.Room, ..)) && args(room, ..)", argNames = "room")
void onLinkUsers(Room room) {
countAllUsers(room);
}
@After(value = "execution(void ru.dragonestia.picker.repository.UserRepository.unlinkWithRoom(ru.dragonestia.picker.model.room.Room, ..)) && args(room, ..)", argNames = "room")
@After(value = "execution(void ru.dragonestia.picker.repository.EntityRepository.unlinkWithRoom(ru.dragonestia.picker.model.room.Room, ..)) && args(room, ..)", argNames = "room")
void onUnlinkUsers(Room room) {
countAllUsers(room);
}
private void countAllUsers(Room room) {
totalUsers.set(userRepository.countAllUsers());
totalUsers.set(entityRepository.countAllEntities());
}
@After(value = "execution(void ru.dragonestia.picker.repository.InstanceRepository.create(ru.dragonestia.picker.model.instance.Instance)) && args(instance)", argNames = "instance")
@ -95,7 +95,7 @@ public class UserMetricsAspect {
@Scheduled(fixedDelay = 3_000)
void updateUserMetrics() {
userRepository.countUsersForNodes().forEach((nodeId, users) -> {
entityRepository.countEntitiesForNodes().forEach((nodeId, users) -> {
Optional.ofNullable(data.get(nodeId)).ifPresent(node -> node.users().set(users));
});

View File

@ -14,14 +14,14 @@ 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.api.repository.type.EntityIdentifier;
import ru.dragonestia.picker.interceptor.DebugInterceptor;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.model.factory.RoomFactory;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.InstanceRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import java.util.List;
import java.util.Random;
@ -34,7 +34,7 @@ public class TestConfig implements WebMvcConfigurer {
private final InstanceRepository instanceRepository;
private final RoomRepository roomRepository;
private final UserRepository userRepository;
private final EntityRepository entityRepository;
private final RoomFactory roomFactory;
private final Random rand = new Random(0);
@ -62,8 +62,8 @@ public class TestConfig implements WebMvcConfigurer {
roomRepository.create(room);
for (int j = 0, n = rand.nextInt(slots + 1); j < n; j++) {
var user = new User(UserIdentifier.of("test-user-" + rand.nextInt(20)));
userRepository.linkWithRoom(room, List.of(user), false);
var user = new Entity(EntityIdentifier.of("test-user-" + rand.nextInt(20)));
entityRepository.linkWithRoom(room, List.of(user), false);
}
}

View File

@ -9,16 +9,16 @@ 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 = "User management")
@Tag(name = "Users", description = "Entity management")
@RequiredArgsConstructor
@RestController
@RequestMapping("/users")
public class UserController {
public class EntityController {
@Operation(summary = "Search user by identifier")
@GetMapping("/search")
SearchUserResponse search(
@Parameter(description = "User identifier input") @RequestParam(name = "input") String input
@Parameter(description = "Entity identifier input") @RequestParam(name = "input") String input
) {
throw new UnsupportedOperationException("Not implemented");
}
@ -26,7 +26,7 @@ public class UserController {
@Operation(summary = "Get user info")
@GetMapping("/{userId}")
UserDetailsResponse find(
@Parameter(description = "User identifier") @PathVariable(value = "userId") String userId
@Parameter(description = "Entity identifier") @PathVariable(value = "userId") String userId
) {
throw new UnsupportedOperationException("Not implemented");
}
@ -34,7 +34,7 @@ public class UserController {
@Operation(summary = "Get rooms linked with user")
@GetMapping("/{userId}/rooms")
LinkedRoomsWithUserResponse roomsOf(
@Parameter(description = "User identifier") @PathVariable(value = "userId") String userId
@Parameter(description = "Entity identifier") @PathVariable(value = "userId") String userId
) {
throw new UnsupportedOperationException("Not implemented");
}

View File

@ -9,18 +9,17 @@ 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 = "User management")
@Tag(name = "Users", description = "Entity management")
@RequiredArgsConstructor
@RestController
@RequestMapping("/nodes/{nodeId}/rooms/{roomId}/users")
public class UserRoomController {
@RequestMapping("/instances/{instanceId}/rooms/{roomId}/users")
public class EntityRoomController {
@Operation(summary = "Get users inside room")
@GetMapping
ResponseEntity<RoomUserListResponse> usersInsideRoom(
@Parameter(description = "Instance identifier") @PathVariable(name = "nodeId") String nodeId,
@Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId,
@Parameter(description = "Required addition user data", example = "COUNT_ROOMS") @RequestParam(name = "requiredDetails", required = false, defaultValue = "") String detailsSeq
@Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId,
@Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId
) {
throw new UnsupportedOperationException("Not implemented");
}
@ -28,9 +27,9 @@ public class UserRoomController {
@Operation(summary = "Link users with room")
@PostMapping
ResponseEntity<LinkUsersWithRoomResponse> linkUserWithRoom(
@Parameter(description = "Instance identifier") @PathVariable(name = "nodeId") String nodeId,
@Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId,
@Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId,
@Parameter(description = "User identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds,
@Parameter(description = "Entity identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds,
@Parameter(description = "Ignore slot limitation") @RequestParam(name = "force") boolean force
) {
throw new UnsupportedOperationException("Not implemented");
@ -39,9 +38,9 @@ public class UserRoomController {
@Operation(summary = "Unlink users from room")
@DeleteMapping
ResponseEntity<?> unlinkUsersForBucket(
@Parameter(description = "Instance identifier") @PathVariable(name = "nodeId") String nodeId,
@Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId,
@Parameter(description = "Room identifier") @PathVariable(name = "roomId") String roomId,
@Parameter(description = "User identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds
@Parameter(description = "Entity identifiers", example = "user1,user2,user3") @RequestParam(name = "userIds") String userIds
) {
throw new UnsupportedOperationException("Not implemented");
}

View File

@ -11,8 +11,8 @@ import java.util.HashMap;
@RestControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler(NodeNotFoundException.class)
ResponseEntity<?> nodeNotFound(NodeNotFoundException ex) {
@ExceptionHandler(InstanceNotFoundException.class)
ResponseEntity<?> nodeNotFound(InstanceNotFoundException ex) {
return create(404, ex);
}
@ -36,8 +36,8 @@ public class ExceptionHandlerController {
return create(400, ex);
}
@ExceptionHandler(NodeAlreadyExistException.class)
ResponseEntity<?> nodeAlreadyExists(NodeAlreadyExistException ex) {
@ExceptionHandler(InstanceAlreadyExistException.class)
ResponseEntity<?> nodeAlreadyExists(InstanceAlreadyExistException ex) {
return create(400, ex);
}

View File

@ -13,20 +13,20 @@ import ru.dragonestia.picker.api.repository.response.PickedRoomResponse;
@Tag(name = "Nodes", description = "Instance management")
@RestController
@RequestMapping("/nodes")
@RequestMapping("/instances")
@RequiredArgsConstructor
public class NodeController {
public class InstanceController {
@Operation(summary = "Get all nodes")
@GetMapping
NodeListResponse allNodes() {
NodeListResponse allInstances() {
throw new UnsupportedOperationException("Not implemented");
}
@Operation(summary = "Register new node")
@PostMapping
ResponseEntity<?> registerNode(
@Parameter(description = "Instance identifier") @RequestParam(name = "nodeId") String nodeId,
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
) {
@ -34,25 +34,25 @@ public class NodeController {
}
@Operation(summary = "Get node details")
@GetMapping("/{nodeId}")
ResponseEntity<NodeDetailsResponse> nodeDetails(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId
@GetMapping("/{instanceId}")
ResponseEntity<NodeDetailsResponse> instanceDetails(
@Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId
) {
throw new UnsupportedOperationException("Not implemented");
}
@Operation(summary = "Unregister node")
@DeleteMapping("/{nodeId}")
ResponseEntity<?> removeNode(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId
@DeleteMapping("/{instanceId}")
ResponseEntity<?> removeInstance(
@Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId
) {
throw new UnsupportedOperationException("Not implemented");
}
@Operation(summary = "Pick node for users")
@PostMapping("/{nodeId}/pick")
@PostMapping("/{instanceId}/pick")
ResponseEntity<PickedRoomResponse> pickRoom(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId,
@Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId,
@RequestBody String userIds
) {
throw new UnsupportedOperationException("Not implemented");

View File

@ -12,14 +12,14 @@ import ru.dragonestia.picker.api.repository.response.RoomListResponse;
@Tag(name = "Rooms", description = "Room management")
@RestController
@RequestMapping("/nodes/{nodeId}/rooms")
@RequestMapping("/instances/{instanceId}/rooms")
@RequiredArgsConstructor
public class RoomController {
@Operation(summary = "Get all rooms from node")
@GetMapping
ResponseEntity<RoomListResponse> all(
@Parameter(description = "Instance identifier") @PathVariable(name = "nodeId") String nodeId
@Parameter(description = "Instance identifier") @PathVariable(name = "instanceId") String instanceId
) {
throw new UnsupportedOperationException("Not implemented");
}
@ -27,7 +27,7 @@ public class RoomController {
@Operation(summary = "Register new room")
@PostMapping
ResponseEntity<?> register(
@Parameter(description = "Instance identifier") @PathVariable(name = "nodeId") String nodeId,
@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,
@ -40,7 +40,7 @@ public class RoomController {
@Operation(summary = "Unregister room")
@DeleteMapping("/{roomId}")
ResponseEntity<?> remove(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId,
@Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId,
@Parameter(description = "Room identifier") @PathVariable("roomId") String roomId
) {
throw new UnsupportedOperationException("Not implemented");
@ -49,7 +49,7 @@ public class RoomController {
@Operation(summary = "Get room details")
@GetMapping("/{roomId}")
ResponseEntity<RoomInfoResponse> info(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId,
@Parameter(description = "Instance identifier") @PathVariable("instanceId") String instanceId,
@Parameter(description = "Room identifier") @PathVariable("roomId") String roomId
) {
throw new UnsupportedOperationException("Not implemented");
@ -59,7 +59,7 @@ public class RoomController {
@ApiResponse(description = "New lock state")
@PutMapping("/{roomId}/lock")
ResponseEntity<Boolean> lockRoom(
@Parameter(description = "Instance identifier") @PathVariable("nodeId") String nodeId,
@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
) {

View File

@ -4,15 +4,15 @@ 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.UserIdentifier;
import ru.dragonestia.picker.controller.graphql.entity.EntityInstance;
import ru.dragonestia.picker.controller.graphql.entity.EntityRoom;
import ru.dragonestia.picker.controller.graphql.entity.EntityUser;
import ru.dragonestia.picker.controller.graphql.entity.type.DataProvider;
import ru.dragonestia.picker.model.user.User;
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.service.InstanceService;
import ru.dragonestia.picker.service.RoomService;
import ru.dragonestia.picker.service.UserService;
import ru.dragonestia.picker.service.EntityService;
import java.util.List;
@ -21,59 +21,59 @@ public class GraphqlController {
private final InstanceService instanceService;
private final RoomService roomService;
private final UserService userService;
private final EntityService entityService;
private final DataProvider dataProvider;
public GraphqlController(InstanceService instanceService, RoomService roomService, UserService userService) {
public GraphqlController(InstanceService instanceService, RoomService roomService, EntityService entityService) {
this.instanceService = instanceService;
this.roomService = roomService;
this.userService = userService;
dataProvider = new DataProvider(instanceService, roomService, userService);
this.entityService = entityService;
dataProvider = new DataProvider(instanceService, roomService, entityService);
}
@QueryMapping
List<EntityInstance> allInstances() {
List<ObjectInstance> allInstances() {
return instanceService.all().stream()
.map(node -> new EntityInstance(node, dataProvider))
.map(node -> new ObjectInstance(node, dataProvider))
.toList();
}
@QueryMapping
EntityInstance instanceById(@Argument String id) {
ObjectInstance instanceById(@Argument String id) {
return instanceService.find(id)
.map(node -> new EntityInstance(node, dataProvider))
.map(node -> new ObjectInstance(node, dataProvider))
.orElse(null);
}
@QueryMapping
List<EntityRoom> allRooms(@NotNull String nodeId) {
List<ObjectRoom> allRooms(@NotNull String nodeId) {
var node = instanceService.find(nodeId).orElse(null);
if (node == null) return null;
return roomService.all(node).stream()
.map(room -> new EntityRoom(room, dataProvider))
.map(room -> new ObjectRoom(room, dataProvider))
.toList();
}
@QueryMapping
EntityRoom roomById(@Argument String nodeId, @NotNull String roomId) {
ObjectRoom roomById(@Argument String nodeId, @NotNull String roomId) {
var node = instanceService.find(nodeId).orElse(null);
if (node == null) return null;
return roomService.find(node, roomId)
.map(room -> new EntityRoom(room, dataProvider))
.map(room -> new ObjectRoom(room, dataProvider))
.orElse(null);
}
@QueryMapping
EntityUser userById(@Argument String id) {
return new EntityUser(new User(UserIdentifier.of(id)), dataProvider);
ObjectEntity entityById(@Argument String id) {
return new ObjectEntity(new Entity(EntityIdentifier.of(id)), dataProvider);
}
@QueryMapping
List<EntityUser> searchUser(@Argument String input) {
return userService.searchUsers(input).stream()
.map(user -> new EntityUser(new User(user.getIdentifierObject()), dataProvider))
List<ObjectEntity> searchEntity(@Argument String input) {
return entityService.searchEntities(input).stream()
.map(user -> new ObjectEntity(new Entity(user.getIdentifierObject()), dataProvider))
.toList();
}
}

View File

@ -1,36 +0,0 @@
package ru.dragonestia.picker.controller.graphql.entity;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.controller.graphql.entity.type.DataProvider;
import ru.dragonestia.picker.model.user.User;
import java.util.List;
@RequiredArgsConstructor
public class EntityUser {
private final User user;
private final DataProvider dataProvider;
private List<EntityRoom> cachedRooms = null;
public @NotNull String getId() {
return user.getIdentifier();
}
public List<EntityRoom> getRooms() {
if (cachedRooms != null) {
return cachedRooms;
}
cachedRooms = dataProvider.userService().getUserRooms(user).stream()
.map(room -> new EntityRoom(room, dataProvider))
.toList();
return cachedRooms;
}
public int getCountRooms() {
return getRooms().size();
}
}

View File

@ -0,0 +1,36 @@
package ru.dragonestia.picker.controller.graphql.object;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.controller.graphql.object.type.DataProvider;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.List;
@RequiredArgsConstructor
public class ObjectEntity {
private final Entity entity;
private final DataProvider dataProvider;
private List<ObjectRoom> cachedRooms = null;
public @NotNull String getId() {
return entity.getIdentifier();
}
public List<ObjectRoom> getRooms() {
if (cachedRooms != null) {
return cachedRooms;
}
cachedRooms = dataProvider.entityService().getEntityRooms(entity).stream()
.map(room -> new ObjectRoom(room, dataProvider))
.toList();
return cachedRooms;
}
public int getCountRooms() {
return getRooms().size();
}
}

View File

@ -1,17 +1,17 @@
package ru.dragonestia.picker.controller.graphql.entity;
package ru.dragonestia.picker.controller.graphql.object;
import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.controller.graphql.entity.type.DataProvider;
import ru.dragonestia.picker.controller.graphql.object.type.DataProvider;
import ru.dragonestia.picker.model.instance.Instance;
import java.util.List;
@RequiredArgsConstructor
public class EntityInstance {
public class ObjectInstance {
private final Instance instance;
private final DataProvider dataProvider;
private List<EntityRoom> cachedRooms = null;
private List<ObjectRoom> cachedRooms = null;
public String getId() {
return instance.getIdentifier();
@ -21,13 +21,13 @@ public class EntityInstance {
return instance.getPickingMethod().name();
}
public List<EntityRoom> getRooms() {
public List<ObjectRoom> getRooms() {
if (cachedRooms != null) {
return cachedRooms;
}
cachedRooms = dataProvider.roomService().all(instance).stream()
.map(room -> new EntityRoom(room, dataProvider))
.map(room -> new ObjectRoom(room, dataProvider))
.toList();
return cachedRooms;

View File

@ -1,17 +1,17 @@
package ru.dragonestia.picker.controller.graphql.entity;
package ru.dragonestia.picker.controller.graphql.object;
import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.controller.graphql.entity.type.DataProvider;
import ru.dragonestia.picker.controller.graphql.object.type.DataProvider;
import ru.dragonestia.picker.model.room.Room;
import java.util.List;
@RequiredArgsConstructor
public class EntityRoom {
public class ObjectRoom {
private final Room room;
private final DataProvider dataProvider;
private List<EntityUser> cachedUsers = null;
private List<ObjectEntity> cachedUsers = null;
public String getId() {
return room.getIdentifier();
@ -21,9 +21,9 @@ public class EntityRoom {
return room.getInstanceIdentifier();
}
public EntityInstance getInstance() {
public ObjectInstance getInstance() {
return dataProvider.instanceService().find(room.getInstanceIdentifier())
.map(node -> new EntityInstance(node, dataProvider))
.map(node -> new ObjectInstance(node, dataProvider))
.orElseThrow();
}
@ -39,20 +39,20 @@ public class EntityRoom {
return room.isLocked();
}
public List<EntityUser> getUsers() {
public List<ObjectEntity> getEntities() {
if (cachedUsers != null) {
return cachedUsers;
}
cachedUsers = dataProvider.userService().getRoomUsers(room).stream()
.map(user -> new EntityUser(user, dataProvider))
cachedUsers = dataProvider.entityService().getRoomEntities(room).stream()
.map(user -> new ObjectEntity(user, dataProvider))
.toList();
return cachedUsers;
}
public int getCountUsers() {
return getUsers().size();
public int getCountEntities() {
return getEntities().size();
}
public boolean isPersist() {

View File

@ -1,10 +1,10 @@
package ru.dragonestia.picker.controller.graphql.entity.type;
package ru.dragonestia.picker.controller.graphql.object.type;
import jakarta.validation.constraints.NotNull;
import ru.dragonestia.picker.service.InstanceService;
import ru.dragonestia.picker.service.RoomService;
import ru.dragonestia.picker.service.UserService;
import ru.dragonestia.picker.service.EntityService;
public record DataProvider(@NotNull InstanceService instanceService,
@NotNull RoomService roomService,
@NotNull UserService userService) {}
@NotNull EntityService entityService) {}

View File

@ -1,17 +1,17 @@
package ru.dragonestia.picker.model.user;
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.UserIdentifier;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
public class User implements IUser {
public class Entity implements IUser {
private final String identifier;
public User(@NotNull UserIdentifier identifier) {
public Entity(@NotNull EntityIdentifier identifier) {
this.identifier = identifier.getValue();
}
@ -43,7 +43,7 @@ public class User implements IUser {
public boolean equals(Object object) {
if (object == this) return true;
if (object == null) return false;
if (object instanceof User other) {
if (object instanceof Entity other) {
return identifier.equals(other.identifier);
}
return false;

View File

@ -0,0 +1,25 @@
package ru.dragonestia.picker.repository;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.Collection;
import java.util.Map;
public interface EntityRepository {
void linkWithRoom(Room room, Collection<Entity> entities, boolean force) throws RoomAreFullException;
void unlinkWithRoom(Room room, Collection<Entity> entities);
Collection<Room> findAllLinkedEntityRooms(Entity entity);
Collection<Entity> entitiesOf(Room room);
Collection<Entity> search(String input);
int countAllEntities();
Map<String, Integer> countEntitiesForNodes();
}

View File

@ -1,6 +1,6 @@
package ru.dragonestia.picker.repository;
import ru.dragonestia.picker.api.exception.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import java.util.List;
@ -8,7 +8,7 @@ import java.util.Optional;
public interface InstanceRepository {
void create(Instance instance) throws NodeAlreadyExistException;
void create(Instance instance) throws InstanceAlreadyExistException;
void delete(Instance instance);

View File

@ -4,7 +4,7 @@ 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.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.Collection;
import java.util.Optional;
@ -20,5 +20,5 @@ public interface RoomRepository {
Collection<Room> all(Instance instance);
Room pick(Instance instance, Set<User> users) throws NoRoomsAvailableException;
Room pick(Instance instance, Set<Entity> entities) throws NoRoomsAvailableException;
}

View File

@ -1,25 +0,0 @@
package ru.dragonestia.picker.repository;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import java.util.Collection;
import java.util.Map;
public interface UserRepository {
void linkWithRoom(Room room, Collection<User> users, boolean force) throws RoomAreFullException;
void unlinkWithRoom(Room room, Collection<User> users);
Collection<Room> findAllLinkedUserRooms(User user);
Collection<User> usersOf(Room room);
Collection<User> search(String input);
int countAllUsers();
Map<String, Integer> countUsersForNodes();
}

View File

@ -2,10 +2,10 @@ package ru.dragonestia.picker.repository.impl;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import ru.dragonestia.picker.api.exception.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.impl.container.InstanceContainer;
import ru.dragonestia.picker.repository.impl.type.UserTransaction;
import ru.dragonestia.picker.repository.impl.type.EntityTransaction;
import java.util.Collection;
import java.util.Map;
@ -17,30 +17,30 @@ public class ContainerRepository {
private final Map<String, InstanceContainer> containers = new ConcurrentHashMap<>();
private UserTransaction.Listener transactionListener = transaction -> {};
private EntityTransaction.Listener transactionListener = transaction -> {};
public void create(Instance instance) throws NodeAlreadyExistException {
public void create(Instance instance) throws InstanceAlreadyExistException {
if (containers.containsKey(instance.getIdentifier())) {
throw new NodeAlreadyExistException(instance.getIdentifier());
throw new InstanceAlreadyExistException(instance.getIdentifier());
}
var container = new InstanceContainer(instance, transactionListener);
containers.put(instance.getIdentifier(), container);
}
public void remove(@NotNull String nodeId) {
containers.remove(nodeId);
public void remove(@NotNull String instanceId) {
containers.remove(instanceId);
}
public @NotNull Optional<InstanceContainer> findById(@NotNull String nodeId) {
return Optional.ofNullable(containers.get(nodeId));
public @NotNull Optional<InstanceContainer> findById(@NotNull String instanceId) {
return Optional.ofNullable(containers.get(instanceId));
}
public @NotNull Collection<InstanceContainer> all() {
return containers.values();
}
public void setTransactionListener(@NotNull UserTransaction.Listener transactionListener) {
public void setTransactionListener(@NotNull EntityTransaction.Listener transactionListener) {
this.transactionListener = transactionListener;
}
}

View File

@ -3,12 +3,12 @@ package ru.dragonestia.picker.repository.impl;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
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.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
import java.util.*;
@ -16,18 +16,18 @@ import java.util.concurrent.ConcurrentHashMap;
@Component
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {
public class EntityRepositoryImpl implements EntityRepository {
private final ContainerRepository containerRepository;
private final Map<User, Set<Room>> userRooms = new ConcurrentHashMap<>();
private final Map<Entity, Set<Room>> entityRooms = new ConcurrentHashMap<>();
@PostConstruct
void init() {
containerRepository.setTransactionListener(transaction -> {
synchronized (userRooms) {
for (var user: transaction.target()) {
var set = userRooms.computeIfAbsent(user, k -> new HashSet<>());
synchronized (entityRooms) {
for (var entity: transaction.target()) {
var set = entityRooms.computeIfAbsent(entity, k -> new HashSet<>());
set.add(transaction.room());
}
}
@ -35,61 +35,61 @@ public class UserRepositoryImpl implements UserRepository {
}
@Override
public void linkWithRoom(Room room, Collection<User> users, boolean force) throws RoomAreFullException {
synchronized (userRooms) {
getRoomContainer(room).addUsers(users, force);
public void linkWithRoom(Room room, Collection<Entity> entities, boolean force) throws RoomAreFullException {
synchronized (entityRooms) {
getRoomContainer(room).addEntities(entities, force);
for (var user: users) {
var set = userRooms.computeIfAbsent(user, k -> new HashSet<>());
for (var entity: entities) {
var set = entityRooms.computeIfAbsent(entity, k -> new HashSet<>());
set.add(room);
}
}
}
@Override
public void unlinkWithRoom(Room room, Collection<User> users) {
synchronized (userRooms) {
getRoomContainer(room).removeUsers(users);
public void unlinkWithRoom(Room room, Collection<Entity> entities) {
synchronized (entityRooms) {
getRoomContainer(room).removeEntities(entities);
for (var user: users) {
var set = userRooms.get(user);
for (var entity: entities) {
var set = entityRooms.get(entity);
if (set == null) continue;
set.remove(room);
if (set.isEmpty()) userRooms.remove(user);
if (set.isEmpty()) entityRooms.remove(entity);
}
}
}
@Override
public Collection<Room> findAllLinkedUserRooms(User user) {
var result = userRooms.get(user);
public Collection<Room> findAllLinkedEntityRooms(Entity entity) {
var result = entityRooms.get(entity);
return Collections.unmodifiableSet(result == null? new HashSet<>() : result);
}
@Override
public Collection<User> usersOf(Room room) {
return getRoomContainer(room).allUsers();
public Collection<Entity> entitiesOf(Room room) {
return getRoomContainer(room).allEntities();
}
@Override
public Collection<User> search(String input) {
return userRooms.keySet().stream().filter(user -> user.getIdentifier().startsWith(input)).toList();
public Collection<Entity> search(String input) {
return entityRooms.keySet().stream().filter(entity -> entity.getIdentifier().startsWith(input)).toList();
}
@Override
public int countAllUsers() {
return userRooms.size();
public int countAllEntities() {
return entityRooms.size();
}
@Override
public Map<String, Integer> countUsersForNodes() {
public Map<String, Integer> countEntitiesForNodes() {
var result = new HashMap<String, Integer>();
containerRepository.all().forEach(nodeContainer -> {
var nodeId = nodeContainer.getInstance().getIdentifier();
nodeContainer.allRooms().forEach(roomContainer -> {
result.put(nodeId, result.getOrDefault(nodeId, 0) + roomContainer.countUsers());
result.put(nodeId, result.getOrDefault(nodeId, 0) + roomContainer.countEntities());
});
});
@ -98,7 +98,7 @@ public class UserRepositoryImpl implements UserRepository {
private RoomContainer getRoomContainer(Room room) {
return containerRepository.findById(room.getInstanceIdentifier())
.orElseThrow(() -> new NodeNotFoundException(room.getInstanceIdentifier()))
.orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier()))
.findRoomById(room.getIdentifier())
.orElseThrow(() -> new RoomNotFoundException(room.getInstanceIdentifier(), room.getIdentifier()));
}

View File

@ -2,7 +2,7 @@ package ru.dragonestia.picker.repository.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import ru.dragonestia.picker.api.exception.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.InstanceRepository;
import ru.dragonestia.picker.repository.impl.container.InstanceContainer;
@ -17,7 +17,7 @@ public class InstanceRepositoryImpl implements InstanceRepository {
private final ContainerRepository containerRepository;
@Override
public void create(Instance instance) throws NodeAlreadyExistException {
public void create(Instance instance) throws InstanceAlreadyExistException {
containerRepository.create(instance);
}

View File

@ -3,11 +3,11 @@ 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.NodeNotFoundException;
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.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
@ -24,21 +24,21 @@ public class RoomRepositoryImpl implements RoomRepository {
@Override
public void create(Room room) throws RoomAlreadyExistException {
containerRepository.findById(room.getInstanceIdentifier())
.orElseThrow(() -> new NodeNotFoundException(room.getInstanceIdentifier()))
.orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier()))
.addRoom(room);
}
@Override
public void remove(Room room) {
containerRepository.findById(room.getInstanceIdentifier())
.orElseThrow(() -> new NodeNotFoundException(room.getInstanceIdentifier()))
.orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier()))
.removeRoom(room);
}
@Override
public Optional<Room> find(Instance instance, String identifier) {
return containerRepository.findById(instance.getIdentifier())
.orElseThrow(() -> new NodeNotFoundException(instance.getIdentifier()))
.orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier()))
.findRoomById(identifier)
.map(RoomContainer::getRoom);
}
@ -46,15 +46,15 @@ public class RoomRepositoryImpl implements RoomRepository {
@Override
public Collection<Room> all(Instance instance) {
return containerRepository.findById(instance.getIdentifier())
.orElseThrow(() -> new NodeNotFoundException(instance.getIdentifier()))
.orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier()))
.allRooms()
.stream().map(RoomContainer::getRoom).toList();
}
@Override
public Room pick(Instance instance, Set<User> users) throws NoRoomsAvailableException {
public Room pick(Instance instance, Set<Entity> entities) throws NoRoomsAvailableException {
return containerRepository.findById(instance.getIdentifier())
.orElseThrow(() -> new NodeNotFoundException(instance.getIdentifier()))
.pick(users);
.orElseThrow(() -> new InstanceNotFoundException(instance.getIdentifier()))
.pick(entities);
}
}

View File

@ -5,12 +5,12 @@ import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.exception.RoomAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.picker.LeastPickedPicker;
import ru.dragonestia.picker.repository.impl.picker.RoomPicker;
import ru.dragonestia.picker.repository.impl.picker.RoundRobinPicker;
import ru.dragonestia.picker.repository.impl.picker.SequentialFillingPicker;
import ru.dragonestia.picker.repository.impl.type.UserTransaction;
import ru.dragonestia.picker.repository.impl.type.EntityTransaction;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -21,13 +21,13 @@ public class InstanceContainer {
@Getter
private final Instance instance;
private final UserTransaction.Listener transactionListener;
private final EntityTransaction.Listener transactionListener;
private final RoomPicker picker;
private final ReadWriteLock roomLock = new ReentrantReadWriteLock();
private final Map<String, RoomContainer> rooms = new ConcurrentHashMap<>();
public InstanceContainer(@NotNull Instance instance, @NotNull UserTransaction.Listener transactionListener) {
public InstanceContainer(@NotNull Instance instance, @NotNull EntityTransaction.Listener transactionListener) {
this.instance = instance;
this.transactionListener = transactionListener;
this.picker = initPicker();
@ -92,11 +92,11 @@ public class InstanceContainer {
}
}
public @NotNull Room pick(@NotNull Set<User> users) {
public @NotNull Room pick(@NotNull Set<Entity> entities) {
synchronized (picker) {
var room = picker.pick(users);
room.addUsers(users, false);
transactionListener.accept(new UserTransaction(room.getRoom(), users));
var room = picker.pick(entities);
room.addEntities(entities, false);
transactionListener.accept(new EntityTransaction(room.getRoom(), entities));
return room.getRoom();
}
}

View File

@ -4,7 +4,7 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.picker.LeastPickedPicker;
import java.util.*;
@ -17,87 +17,87 @@ public class RoomContainer {
private final Room room;
private final InstanceContainer container;
private final ReadWriteLock usersLock = new ReentrantReadWriteLock(true);
private final Set<User> users = new HashSet<>();
private final ReadWriteLock entityLock = new ReentrantReadWriteLock(true);
private final Set<Entity> entities = new HashSet<>();
public RoomContainer(@NotNull Room room, @NotNull InstanceContainer container) {
this.room = room;
this.container = container;
}
public void addUsers(@NotNull Collection<User> toAdd, boolean force) {
usersLock.writeLock().lock();
public void addEntities(@NotNull Collection<Entity> toAdd, boolean force) {
entityLock.writeLock().lock();
try {
if (force || canAdd0(toAdd.size())) {
users.addAll(toAdd);
noticePickersAboutUserNumberUpdate();
entities.addAll(toAdd);
noticePickersAboutEntityNumberUpdate();
} else {
throw new RoomAreFullException(room.getInstanceIdentifier(), room.getIdentifier());
}
} finally {
usersLock.writeLock().unlock();
entityLock.writeLock().unlock();
}
}
public void removeUsers(@NotNull Collection<User> toRemove) {
usersLock.writeLock().lock();
public void removeEntities(@NotNull Collection<Entity> toRemove) {
entityLock.writeLock().lock();
try {
users.removeAll(toRemove);
noticePickersAboutUserNumberUpdate();
entities.removeAll(toRemove);
noticePickersAboutEntityNumberUpdate();
} finally {
usersLock.writeLock().unlock();
entityLock.writeLock().unlock();
}
}
public @NotNull Collection<User> removeAllUsers() {
usersLock.writeLock().lock();
public @NotNull Collection<Entity> removeAllEntities() {
entityLock.writeLock().lock();
try {
var set = new HashSet<>(users);
users.clear();
noticePickersAboutUserNumberUpdate();
var set = new HashSet<>(entities);
entities.clear();
noticePickersAboutEntityNumberUpdate();
return set;
} finally {
usersLock.writeLock().unlock();
entityLock.writeLock().unlock();
}
}
public @NotNull Collection<User> allUsers() {
usersLock.readLock().lock();
public @NotNull Collection<Entity> allEntities() {
entityLock.readLock().lock();
try {
return new ArrayList<>(users);
return new ArrayList<>(entities);
} finally {
usersLock.readLock().unlock();
entityLock.readLock().unlock();
}
}
public int countUsers() {
return users.size();
public int countEntities() {
return entities.size();
}
private boolean canAdd0(int users) {
return room.hasUnlimitedSlots() || users + countUsers() <= room.getMaxSlots();
private boolean canAdd0(int entities) {
return room.hasUnlimitedSlots() || entities + countEntities() <= room.getMaxSlots();
}
public boolean canAdd(int users) {
public boolean canAdd(int entities) {
try {
return canAdd0(users);
return canAdd0(entities);
} finally {
usersLock.readLock().unlock();
entityLock.readLock().unlock();
}
}
public boolean canBePicked(int users) {
usersLock.readLock().lock();
public boolean canBePicked(int entities) {
entityLock.readLock().lock();
try {
return !room.isLocked() && canAdd0(users);
return !room.isLocked() && canAdd0(entities);
} finally {
usersLock.readLock().unlock();
entityLock.readLock().unlock();
}
}
private void noticePickersAboutUserNumberUpdate() {
private void noticePickersAboutEntityNumberUpdate() {
if (container.getPicker() instanceof LeastPickedPicker picker) {
picker.updateUsersAmount(room, countUsers());
picker.updateEntitiesAmount(room, countEntities());
}
}
}

View File

@ -4,7 +4,7 @@ import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.api.exception.NoRoomsAvailableException;
import ru.dragonestia.picker.api.model.node.PickingMethod;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.collection.DynamicSortedMap;
import ru.dragonestia.picker.repository.impl.container.InstanceContainer;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
@ -32,14 +32,14 @@ public class LeastPickedPicker implements RoomPicker {
}
@Override
public RoomContainer pick(Collection<User> users) {
public RoomContainer pick(Collection<Entity> entities) {
RoomWrapper wrapper;
synchronized (map) {
try {
wrapper = map.getMinimum();
if (!wrapper.canAddUnits(users.size())) throw new RuntimeException();
if (!wrapper.canAddUnits(entities.size())) throw new RuntimeException();
} catch (RuntimeException ex) {
throw new NoRoomsAvailableException(container.getInstance().getIdentifier());
}
@ -48,7 +48,7 @@ public class LeastPickedPicker implements RoomPicker {
return wrapper.getItem();
}
public void updateUsersAmount(Room room, int users) {
public void updateEntitiesAmount(Room room, int users) {
synchronized (map) {
map.updateItem(room.getIdentifier(), prevValue -> users);
}

View File

@ -1,10 +1,10 @@
package ru.dragonestia.picker.repository.impl.picker;
import ru.dragonestia.picker.api.model.node.PickingMethod;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
public interface RoomPicker extends Picker<RoomContainer, User> {
public interface RoomPicker extends Picker<RoomContainer, Entity> {
PickingMethod getPickingMode();
}

View File

@ -22,7 +22,7 @@ public class RoomWrapper implements ItemWrapper<RoomContainer>, QueuedLinkedList
@Override
public int countUnits() {
return container.countUsers();
return container.countEntities();
}
@Override

View File

@ -3,7 +3,7 @@ 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.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.collection.QueuedLinkedList;
import ru.dragonestia.picker.repository.impl.container.InstanceContainer;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
@ -33,8 +33,8 @@ public class RoundRobinPicker implements RoomPicker {
}
@Override
public RoomContainer pick(Collection<User> users) {
int amount = users.size();
public RoomContainer pick(Collection<Entity> entities) {
int amount = entities.size();
RoomWrapper wrapper;
synchronized (list) {

View File

@ -3,7 +3,7 @@ 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.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.impl.container.InstanceContainer;
import ru.dragonestia.picker.repository.impl.container.RoomContainer;
@ -32,8 +32,8 @@ public class SequentialFillingPicker implements RoomPicker {
}
@Override
public RoomContainer pick(Collection<User> users) {
int amount = users.size();
public RoomContainer pick(Collection<Entity> entities) {
int amount = entities.size();
synchronized (wrappers) {
for (var wrapper: wrappers.values()) {

View File

@ -2,12 +2,12 @@ package ru.dragonestia.picker.repository.impl.type;
import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.Collection;
import java.util.function.Consumer;
public record UserTransaction(@NotNull Room room, Collection<User> target) {
public record EntityTransaction(@NotNull Room room, Collection<Entity> target) {
public interface Listener extends Consumer<UserTransaction> {}
public interface Listener extends Consumer<EntityTransaction> {}
}

View File

@ -0,0 +1,24 @@
package ru.dragonestia.picker.service;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.api.model.user.ResponseUser;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.Collection;
import java.util.List;
public interface EntityService {
Collection<Room> getEntityRooms(Entity entity);
void linkEntitiesWithRoom(Room room, Collection<Entity> entities, boolean force) throws RoomAreFullException;
void unlinkEntitiesFromRoom(Room room, Collection<Entity> entities);
Collection<Entity> getRoomEntities(Room room);
List<ResponseUser> searchEntities(String input);
ResponseUser getEntityDetails(String userId);
}

View File

@ -2,7 +2,7 @@ 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.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import java.util.List;
@ -11,7 +11,7 @@ import java.util.Optional;
public interface InstanceService {
@PreAuthorize("hasRole('NODE_MANAGEMENT')")
void create(Instance instance) throws InvalidInstanceIdentifierException, NodeAlreadyExistException;
void create(Instance instance) throws InvalidInstanceIdentifierException, InstanceAlreadyExistException;
@PreAuthorize("hasRole('NODE_MANAGEMENT')")
void remove(Instance instance);

View File

@ -5,7 +5,7 @@ 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.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.Collection;
import java.util.Optional;
@ -21,7 +21,7 @@ public interface RoomService {
Collection<Room> all(Instance instance);
PickedRoomResponse pickAvailable(Instance instance, Set<User> users);
PickedRoomResponse pickAvailable(Instance instance, Set<Entity> entities);
void updateState(Room room);
}

View File

@ -1,24 +0,0 @@
package ru.dragonestia.picker.service;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.api.model.user.ResponseUser;
import ru.dragonestia.picker.model.room.Room;
import ru.dragonestia.picker.model.user.User;
import java.util.Collection;
import java.util.List;
public interface UserService {
Collection<Room> getUserRooms(User user);
void linkUsersWithRoom(Room room, Collection<User> users, boolean force) throws RoomAreFullException;
void unlinkUsersFromRoom(Room room, Collection<User> users);
Collection<User> getRoomUsers(Room room);
List<ResponseUser> searchUsers(String input);
ResponseUser getUserDetails(String userId);
}

View File

@ -74,7 +74,7 @@ public class AccountServiceImpl implements AccountService {
return accounts.get(lowerUsername);
}
throw new UsernameNotFoundException("User '" + username + "' does not exists");
throw new UsernameNotFoundException("Entity '" + username + "' does not exists");
}
private void checkAdmin(String accountId) {

View File

@ -0,0 +1,48 @@
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.room.Room;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.service.EntityService;
import java.util.*;
@RequiredArgsConstructor
@Service
public class EntityServiceImpl implements EntityService {
private final EntityRepository entityRepository;
@Override
public Collection<Room> getEntityRooms(Entity entity) {
return entityRepository.findAllLinkedEntityRooms(entity);
}
@Override
public void linkEntitiesWithRoom(Room room, Collection<Entity> entities, boolean force) {
entityRepository.linkWithRoom(room, entities, force);
}
@Override
public void unlinkEntitiesFromRoom(Room room, Collection<Entity> entities) {
entityRepository.unlinkWithRoom(room, entities);
}
@Override
public Collection<Entity> getRoomEntities(Room room) {
return entityRepository.entitiesOf(room);
}
@Override
public List<ResponseUser> searchEntities(String input) {
return entityRepository.search(input).stream().map(Entity::toResponseObject).toList();
}
@Override
public ResponseUser getEntityDetails(String userId) {
throw new UnsupportedOperationException("Not implemented");
}
}

View File

@ -3,7 +3,7 @@ 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.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.InstanceRepository;
import ru.dragonestia.picker.repository.RoomRepository;
@ -22,7 +22,7 @@ public class InstanceServiceImpl implements InstanceService {
private final InstanceAndRoomStorage storage;
@Override
public void create(Instance instance) throws InvalidInstanceIdentifierException, NodeAlreadyExistException {
public void create(Instance instance) throws InvalidInstanceIdentifierException, InstanceAlreadyExistException {
instanceRepository.create(instance);
storage.saveInstance(instance);
}

View File

@ -4,19 +4,18 @@ 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.NodeNotFoundException;
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.model.room.Room;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.repository.InstanceRepository;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.service.RoomService;
import ru.dragonestia.picker.storage.InstanceAndRoomStorage;
import ru.dragonestia.picker.util.NamingValidator;
import java.util.*;
import java.util.stream.Collectors;
@ -28,15 +27,12 @@ public class RoomServiceImpl implements RoomService {
private final RoomRepository roomRepository;
private final InstanceRepository instanceRepository;
private final UserRepository userRepository;
private final NamingValidator namingValidator;
private final EntityRepository entityRepository;
private final InstanceAndRoomStorage storage;
@Override
public void create(Room room) throws InvalidRoomIdentifierException, RoomAlreadyExistException, NotPersistedNodeException {
namingValidator.validateRoomId(room.getInstanceIdentifier(), room.getIdentifier());
var node = instanceRepository.findById(room.getInstanceIdentifier()).orElseThrow(() -> new NodeNotFoundException(room.getInstanceIdentifier()));
var node = instanceRepository.findById(room.getInstanceIdentifier()).orElseThrow(() -> new InstanceNotFoundException(room.getInstanceIdentifier()));
if (!node.isPersist() && room.isPersist()) {
throw new NotPersistedNodeException(node.getIdentifier(), room.getIdentifier());
}
@ -62,9 +58,9 @@ public class RoomServiceImpl implements RoomService {
}
@Override
public PickedRoomResponse pickAvailable(Instance instance, Set<User> users) {
var room = roomRepository.pick(instance, users);
var roomUsers = userRepository.usersOf(room);
public PickedRoomResponse pickAvailable(Instance instance, Set<Entity> entities) {
var room = roomRepository.pick(instance, entities);
var roomUsers = entityRepository.entitiesOf(room);
return new PickedRoomResponse(
room.getInstanceIdentifier(),
@ -73,7 +69,7 @@ public class RoomServiceImpl implements RoomService {
room.getMaxSlots(),
roomUsers.size(),
room.isLocked(),
roomUsers.stream().map(User::getIdentifier).collect(Collectors.toSet())
roomUsers.stream().map(Entity::getIdentifier).collect(Collectors.toSet())
);
}

View File

@ -1,48 +0,0 @@
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.room.Room;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.service.UserService;
import java.util.*;
@RequiredArgsConstructor
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Override
public Collection<Room> getUserRooms(User user) {
return userRepository.findAllLinkedUserRooms(user);
}
@Override
public void linkUsersWithRoom(Room room, Collection<User> users, boolean force) {
userRepository.linkWithRoom(room, users, force);
}
@Override
public void unlinkUsersFromRoom(Room room, Collection<User> users) {
userRepository.unlinkWithRoom(room, users);
}
@Override
public Collection<User> getRoomUsers(Room room) {
return userRepository.usersOf(room);
}
@Override
public List<ResponseUser> searchUsers(String input) {
return userRepository.search(input).stream().map(User::toResponseObject).toList();
}
@Override
public ResponseUser getUserDetails(String userId) {
throw new UnsupportedOperationException("Not implemented");
}
}

View File

@ -1,50 +0,0 @@
package ru.dragonestia.picker.util;
import org.springframework.stereotype.Component;
import ru.dragonestia.picker.api.exception.InvalidInstanceIdentifierException;
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.User;
import java.util.Collection;
import java.util.LinkedList;
@Component
public class NamingValidator {
public void validateInstanceId(String input) throws InvalidInstanceIdentifierException {
if (IdentifierValidator.forNode(input)) return;
throw new InvalidInstanceIdentifierException(input);
}
public void validateRoomId(String nodeId, String input) throws InvalidRoomIdentifierException {
if (IdentifierValidator.forRoom(input)) return;
throw new InvalidRoomIdentifierException(nodeId, input);
}
public boolean validateUserId(String input) {
return IdentifierValidator.forUser(input);
}
public void validateUserIds(Collection<String> input) throws InvalidUsernamesException {
var users = new LinkedList<User>();
var invalid = new LinkedList<String>();
for (var username: input) {
if (validateUserId(username)) {
users.add(new User(UserIdentifier.of(username)));
continue;
}
invalid.add(username);
}
if (!invalid.isEmpty()) {
throw new InvalidUsernamesException(input.stream().toList(), invalid);
}
}
}

View File

@ -3,8 +3,8 @@ type Query {
instanceById(id: String!): Instance
allRooms(nodeId: String!): [Room]
roomById(nodeId: String!, roomId: String!): Room
userById(id: String!): User!
searchUser(input: String!): [User]
entityById(id: String!): Entity!
searchEntity(input: String!): [Entity]
}
type Instance {
@ -22,12 +22,12 @@ type Room {
slots: Int!
payload: String!
locked: Boolean!
users: [User]
countUsers: Int!
entities: [Entity]
countEntities: Int!
persist: Boolean!
}
type User {
type Entity {
id: String!
rooms: [Room]
countRooms: Int!

View File

@ -6,13 +6,13 @@ 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.api.repository.type.EntityIdentifier;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.model.factory.RoomFactory;
import ru.dragonestia.picker.repository.InstanceRepository;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import java.util.List;
@ -45,7 +45,7 @@ public class FillingNodesConfig {
private RoomRepository roomRepository;
@Autowired
private UserRepository userRepository;
private EntityRepository entityRepository;
@Autowired
private RoomFactory roomFactory;
@ -93,8 +93,8 @@ public class FillingNodesConfig {
var users = n - i;
for (int k = users - 1; k >= 0; k--) {
var user = new User(UserIdentifier.of("user-" + k));
userRepository.linkWithRoom(room, List.of(user), false);
var user = new Entity(EntityIdentifier.of("user-" + k));
entityRepository.linkWithRoom(room, List.of(user), false);
}
//System.out.printf("Room '%s' has %s/%s users%n", roomId, users, n);

View File

@ -14,7 +14,7 @@ import ru.dragonestia.picker.api.exception.NoRoomsAvailableException;
import ru.dragonestia.picker.config.FillingNodesConfig;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.util.UserFiller;
import java.util.stream.Stream;
@ -28,7 +28,7 @@ public class LeastPickedTests {
private RoomRepository roomRepository;
@Autowired
private UserRepository userRepository;
private EntityRepository entityRepository;
@Autowired
private UserFiller userFiller;
@ -41,11 +41,11 @@ public class LeastPickedTests {
@ParameterizedTest
@ArgumentsSource(PickingArgumentProvider.class)
void testPicking(String expectedRoomId, int usersAmount) {
var expectedRoomUsers = userRepository.usersOf(roomRepository.find(instance, expectedRoomId).orElseThrow()).size();
var expectedRoomUsers = entityRepository.entitiesOf(roomRepository.find(instance, expectedRoomId).orElseThrow()).size();
var room = roomRepository.pick(instance, userFiller.createRandomUsers(usersAmount));
var slots = room.getMaxSlots();
var users = userRepository.usersOf(room);
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);

View File

@ -12,7 +12,7 @@ import ru.dragonestia.picker.api.exception.NoRoomsAvailableException;
import ru.dragonestia.picker.config.FillingNodesConfig;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.util.UserFiller;
import java.util.stream.Stream;
@ -26,7 +26,7 @@ public class RoundRobinTests {
private RoomRepository roomRepository;
@Autowired
private UserRepository userRepository;
private EntityRepository entityRepository;
@Autowired
private UserFiller userFiller;
@ -41,7 +41,7 @@ public class RoundRobinTests {
void testPicking(String expectedRoomId, int usersAmount) {
var room = roomRepository.pick(instance, userFiller.createRandomUsers(usersAmount));
var slots = room.getMaxSlots();
var users = userRepository.usersOf(room);
var users = entityRepository.entitiesOf(room);
Assertions.assertTrue(slots == -1 || slots >= users.size()); // check slots limitation
Assertions.assertEquals(expectedRoomId, room.getIdentifier());

View File

@ -14,7 +14,7 @@ import ru.dragonestia.picker.api.exception.NoRoomsAvailableException;
import ru.dragonestia.picker.config.FillingNodesConfig;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.repository.RoomRepository;
import ru.dragonestia.picker.repository.UserRepository;
import ru.dragonestia.picker.repository.EntityRepository;
import ru.dragonestia.picker.util.UserFiller;
import java.util.stream.Stream;
@ -28,7 +28,7 @@ public class SequentialFillingTests {
private RoomRepository roomRepository;
@Autowired
private UserRepository userRepository;
private EntityRepository entityRepository;
@Autowired
private UserFiller userFiller;
@ -41,11 +41,11 @@ public class SequentialFillingTests {
@ParameterizedTest
@ArgumentsSource(PickingArgumentProvider.class)
void testPicking(String expectedRoomId, int usersAmount) {
var expectedRoomUsers = userRepository.usersOf(roomRepository.find(instance, expectedRoomId).orElseThrow()).size();
var expectedRoomUsers = entityRepository.entitiesOf(roomRepository.find(instance, expectedRoomId).orElseThrow()).size();
var room = roomRepository.pick(instance, userFiller.createRandomUsers(usersAmount));
var slots = room.getMaxSlots();
var users = userRepository.usersOf(room);
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);

View File

@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import ru.dragonestia.picker.api.exception.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
import ru.dragonestia.picker.api.model.node.PickingMethod;
import ru.dragonestia.picker.api.repository.type.NodeIdentifier;
import ru.dragonestia.picker.model.instance.Instance;
@ -25,7 +25,7 @@ public class InstanceServiceTests {
Assertions.assertDoesNotThrow(() -> instanceService.create(node));
Assertions.assertTrue(instanceService.find(node.getIdentifier()).isPresent());
Assertions.assertThrows(NodeAlreadyExistException.class, () -> instanceService.create(node));
Assertions.assertThrows(InstanceAlreadyExistException.class, () -> instanceService.create(node));
instanceService.remove(node);

View File

@ -6,17 +6,17 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import ru.dragonestia.picker.api.exception.NodeAlreadyExistException;
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
import ru.dragonestia.picker.api.exception.InstanceAlreadyExistException;
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.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.api.repository.type.EntityIdentifier;
import ru.dragonestia.picker.model.instance.Instance;
import ru.dragonestia.picker.model.user.User;
import ru.dragonestia.picker.model.entity.Entity;
import ru.dragonestia.picker.model.factory.RoomFactory;
import java.util.List;
@ -42,7 +42,7 @@ public class RoomServiceTests {
try {
instanceService.create(instance);
} catch (NodeAlreadyExistException ignore) {}
} catch (InstanceAlreadyExistException ignore) {}
}
@WithMockUser(roles = {"NODE_MANAGEMENT"})
@ -98,12 +98,12 @@ public class RoomServiceTests {
rooms.forEach(room -> roomService.create(room));
var users = Set.of(
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"))
new Entity(EntityIdentifier.of("1")),
new Entity(EntityIdentifier.of("2")),
new Entity(EntityIdentifier.of("3")),
new Entity(EntityIdentifier.of("4")),
new Entity(EntityIdentifier.of("5")),
new Entity(EntityIdentifier.of("6"))
);
@ -115,7 +115,7 @@ public class RoomServiceTests {
void test_removeNode() {
instanceService.remove(instance);
Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.all(instance));
Assertions.assertThrows(InstanceNotFoundException.class, () -> roomService.all(instance));
}
@WithMockUser(roles = {"NODE_MANAGEMENT"})
@ -124,9 +124,9 @@ public class RoomServiceTests {
var node = new Instance(NodeIdentifier.of("bruh"), PickingMethod.ROUND_ROBIN, false);
var room = roomFactory.create(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, Set.of(new User(UserIdentifier.of("1")))));
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")))));
}
}

View File

@ -1,18 +1,18 @@
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.User;
import ru.dragonestia.picker.api.repository.type.EntityIdentifier;
import ru.dragonestia.picker.model.entity.Entity;
import java.util.*;
@TestComponent
public class UserFiller {
public Set<User> createRandomUsers(int amount) {
var set = new HashSet<User>();
public Set<Entity> createRandomUsers(int amount) {
var set = new HashSet<Entity>();
for (int i = 0; i < amount; i++) {
set.add(new User(UserIdentifier.of(UUID.randomUUID().toString())));
set.add(new Entity(EntityIdentifier.of(UUID.randomUUID().toString())));
}
return set;
}