From bde58ef053ca4f61c64dc72a916d426bbc098c9e Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Tue, 12 Mar 2024 15:19:48 +0700 Subject: [PATCH] Created base for client implementation --- client-impl/build.gradle | 4 +- .../picker/api/impl/RoomPickerClient.java | 59 +++++++++ .../impl/repository/NodeRepositoryImpl.java | 50 ++++++++ .../impl/repository/RoomRepositoryImpl.java | 52 ++++++++ .../impl/repository/UserRepositoryImpl.java | 52 ++++++++ .../picker/api/impl/util/RestTemplate.java | 114 ++++++++++++++++++ .../picker/api/impl/util/type/HttpMethod.java | 8 ++ 7 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/NodeRepositoryImpl.java create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/RoomRepositoryImpl.java create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/UserRepositoryImpl.java create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/RestTemplate.java create mode 100644 client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/type/HttpMethod.java diff --git a/client-impl/build.gradle b/client-impl/build.gradle index 921ceb4..0c1b60b 100644 --- a/client-impl/build.gradle +++ b/client-impl/build.gradle @@ -12,7 +12,9 @@ repositories { dependencies { implementation project(':client-api') implementation 'org.jetbrains:annotations:24.1.0' - implementation 'com.squareup.okhttp:okhttp:2.7.5' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3' testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java new file mode 100644 index 0000000..2c6f085 --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java @@ -0,0 +1,59 @@ +package ru.dragonestia.picker.api.impl; + +import okhttp3.Credentials; +import okhttp3.Request; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ApiStatus.Internal; + +import ru.dragonestia.picker.api.impl.repository.NodeRepositoryImpl; +import ru.dragonestia.picker.api.impl.repository.RoomRepositoryImpl; +import ru.dragonestia.picker.api.impl.repository.UserRepositoryImpl; +import ru.dragonestia.picker.api.impl.util.RestTemplate; +import ru.dragonestia.picker.api.repository.NodeRepository; +import ru.dragonestia.picker.api.repository.RoomRepository; +import ru.dragonestia.picker.api.repository.UserRepository; + +public class RoomPickerClient { + + private final String url; + private final String username; + private final String password; + private final RestTemplate restTemplate; + private final NodeRepository nodeRepository; + private final RoomRepository roomRepository; + private final UserRepository userRepository; + + public RoomPickerClient(@NotNull String url, @NotNull String username, @NotNull String password) { + this.url = url; + this.username = username; + this.password = password; + this.restTemplate = new RestTemplate(this); + this.nodeRepository = new NodeRepositoryImpl(this); + this.roomRepository = new RoomRepositoryImpl(this); + this.userRepository = new UserRepositoryImpl(this); + } + + @Internal + public @NotNull RestTemplate getRestTemplate() { + return restTemplate; + } + + @Internal + public @NotNull Request.Builder prepareRequestBuilder(@NotNull String uri) { + return new Request.Builder() + .url(url + uri) + .addHeader("Authorization", Credentials.basic(username, password)); + } + + public @NotNull NodeRepository getNodeRepository() { + return nodeRepository; + } + + public @NotNull RoomRepository getRoomRepository() { + return roomRepository; + } + + public @NotNull UserRepository getUserRepository() { + return userRepository; + } +} diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/NodeRepositoryImpl.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/NodeRepositoryImpl.java new file mode 100644 index 0000000..b0b0d55 --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/NodeRepositoryImpl.java @@ -0,0 +1,50 @@ +package ru.dragonestia.picker.api.impl.repository; + +import org.jetbrains.annotations.ApiStatus.Internal; +import org.jetbrains.annotations.NotNull; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.impl.util.RestTemplate; +import ru.dragonestia.picker.api.model.node.INode; +import ru.dragonestia.picker.api.model.node.NodeDefinition; +import ru.dragonestia.picker.api.repository.NodeRepository; +import ru.dragonestia.picker.api.repository.request.node.FindNodeById; +import ru.dragonestia.picker.api.repository.request.node.GetAllNodes; +import ru.dragonestia.picker.api.repository.request.node.RemoveNodesByIds; + +import java.util.List; +import java.util.Optional; + +public class NodeRepositoryImpl implements NodeRepository { + + private final RestTemplate rest; + + @Internal + public NodeRepositoryImpl(RoomPickerClient client) { + rest = client.getRestTemplate(); + } + + @Override + public @NotNull List allNodes(@NotNull GetAllNodes data) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull Optional findNodeById(@NotNull FindNodeById data) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void removeNodesById(@NotNull RemoveNodesByIds data) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void removeNode(@NotNull INode node) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void saveNode(@NotNull NodeDefinition definition) { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/RoomRepositoryImpl.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/RoomRepositoryImpl.java new file mode 100644 index 0000000..d2c1aeb --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/RoomRepositoryImpl.java @@ -0,0 +1,52 @@ +package ru.dragonestia.picker.api.impl.repository; + +import org.jetbrains.annotations.ApiStatus.Internal; +import org.jetbrains.annotations.NotNull; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.impl.util.RestTemplate; +import ru.dragonestia.picker.api.model.room.ResponseRoom; +import ru.dragonestia.picker.api.model.room.RoomDefinition; +import ru.dragonestia.picker.api.model.room.ShortResponseRoom; +import ru.dragonestia.picker.api.repository.RoomRepository; +import ru.dragonestia.picker.api.repository.request.room.FindRoomById; +import ru.dragonestia.picker.api.repository.request.room.GetAllRooms; +import ru.dragonestia.picker.api.repository.request.room.RemoveRoomsByIds; +import ru.dragonestia.picker.api.repository.type.RoomPath; + +import java.util.List; +import java.util.Optional; + +public class RoomRepositoryImpl implements RoomRepository { + + private final RestTemplate rest; + + @Internal + public RoomRepositoryImpl(RoomPickerClient client) { + rest = client.getRestTemplate(); + } + + @Override + public void saveRoom(@NotNull RoomDefinition definition) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void removeRooms(@NotNull RemoveRoomsByIds request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull List allRooms(@NotNull GetAllRooms request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull Optional find(@NotNull FindRoomById request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void lockRoom(@NotNull RoomPath path, boolean value) { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/UserRepositoryImpl.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/UserRepositoryImpl.java new file mode 100644 index 0000000..0256db3 --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/UserRepositoryImpl.java @@ -0,0 +1,52 @@ +package ru.dragonestia.picker.api.impl.repository; + +import org.jetbrains.annotations.ApiStatus.Internal; +import org.jetbrains.annotations.NotNull; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.impl.util.RestTemplate; +import ru.dragonestia.picker.api.model.room.ShortResponseRoom; +import ru.dragonestia.picker.api.model.user.ResponseUser; +import ru.dragonestia.picker.api.repository.UserRepository; +import ru.dragonestia.picker.api.repository.request.user.*; + +import java.util.List; + +public class UserRepositoryImpl implements UserRepository { + + private final RestTemplate rest; + + @Internal + public UserRepositoryImpl(RoomPickerClient client) { + rest = client.getRestTemplate(); + } + + @Override + public void linkUsersWithRoom(@NotNull LinkUsersWithRoom request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void unlinkUsersFromRoom(@NotNull UnlinkUsersFromRoom request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull List getAllUsersFormRoom(@NotNull GetAllUsersFromRoom request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull List searchUsers(@NotNull SearchUsers request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull ResponseUser findUserById(@NotNull FindUserById request) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public @NotNull List findRoomsLinkedWithUser(@NotNull FindRoomsLinkedWithUser request) { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/RestTemplate.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/RestTemplate.java new file mode 100644 index 0000000..1847dcb --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/RestTemplate.java @@ -0,0 +1,114 @@ +package ru.dragonestia.picker.api.impl.util; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Response; +import org.jetbrains.annotations.ApiStatus.Internal; +import ru.dragonestia.picker.api.exception.ExceptionFactory; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.impl.util.type.HttpMethod; +import ru.dragonestia.picker.api.repository.response.ErrorResponse; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.function.Consumer; + +@Internal +public class RestTemplate { + + private final RoomPickerClient client; + private final OkHttpClient httpClient; + private final ObjectMapper json; + + public RestTemplate(RoomPickerClient client) { + this.client = client; + httpClient = new OkHttpClient(); + json = configureJackson(); + } + + private ObjectMapper configureJackson() { + var mapper = new ObjectMapper(); + mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY) + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + .withSetterVisibility(JsonAutoDetect.Visibility.NONE) + .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)); + return mapper; + } + + public void query(String uri, HttpMethod method) { + query(uri, method, ParamsConsumer.NONE); + } + + public void query(String uri, HttpMethod method, ParamsConsumer paramsConsumer) { + var request = client.prepareRequestBuilder(uri + queryEncode(paramsConsumer)) + .method(method.name(), method == HttpMethod.GET? null : new FormBody.Builder().build()) + .build(); + + try (var response = httpClient.newCall(request).execute()) { + checkResponseForErrors(response); + } catch (JsonProcessingException ex) { + throw new RuntimeException("Json processing error", ex); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + public T query(String uri, HttpMethod method, Class clazz) { + return query(uri, method, clazz, ParamsConsumer.NONE); + } + + public T query(String uri, HttpMethod method, Class clazz, ParamsConsumer paramsConsumer) { + var request = client.prepareRequestBuilder(uri + queryEncode(paramsConsumer)) + .method(method.name(), method == HttpMethod.GET? null : new FormBody.Builder().build()) + .build(); + + try (var response = httpClient.newCall(request).execute()) { + checkResponseForErrors(response); + + return json.readValue(new String(Objects.requireNonNull(response.body()).bytes(), StandardCharsets.UTF_8), clazz); + } catch (JsonProcessingException ex) { + throw new RuntimeException("Json processing error", ex); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private String queryEncode(ParamsConsumer paramsConsumer) { + var params = new HashMap(); + paramsConsumer.accept(params); + + if (params.isEmpty()) return ""; + + List pairs = new ArrayList<>(); + for (var entry: params.entrySet()) { + pairs.add(entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)); + } + return "?" + String.join("&", pairs); + } + + private void checkResponseForErrors(Response response) throws IOException { + var code = response.code(); + System.out.println(code); + var statusCode = code / 100; + + if (statusCode == 4) { + var body = new String(Objects.requireNonNull(response.body()).bytes(), StandardCharsets.UTF_8); + throw ExceptionFactory.of(json.readValue(body, ErrorResponse.class)); + } + + if (statusCode == 5) { + throw new RuntimeException("Internal server error"); + } + } + + public interface ParamsConsumer extends Consumer> { + + ParamsConsumer NONE = map -> {}; + } +} diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/type/HttpMethod.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/type/HttpMethod.java new file mode 100644 index 0000000..547ef6e --- /dev/null +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/util/type/HttpMethod.java @@ -0,0 +1,8 @@ +package ru.dragonestia.picker.api.impl.util.type; + +public enum HttpMethod { + GET, + POST, + PUT, + DELETE; +}