Skip to content

Commit

Permalink
fix!: Improve generic types
Browse files Browse the repository at this point in the history
  • Loading branch information
brenoepics committed Feb 8, 2024
1 parent 134343b commit 9530643
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 74 deletions.
28 changes: 25 additions & 3 deletions src/main/java/io/github/brenoepics/at4j/AzureApi.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package io.github.brenoepics.at4j;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.brenoepics.at4j.azure.BaseURL;
import io.github.brenoepics.at4j.azure.lang.Language;
import io.github.brenoepics.at4j.core.ratelimit.RateLimitManager;
import io.github.brenoepics.at4j.core.thread.ThreadPool;
import io.github.brenoepics.at4j.data.DetectedLanguage;
import io.github.brenoepics.at4j.data.TranslationResult;
import io.github.brenoepics.at4j.data.request.AvailableLanguagesParams;
import io.github.brenoepics.at4j.data.request.DetectLanguageParams;
import io.github.brenoepics.at4j.data.request.TranslateParams;
import io.github.brenoepics.at4j.data.response.DetectResponse;
import io.github.brenoepics.at4j.data.response.TranslationResponse;
import io.github.brenoepics.at4j.data.TranslationResult;

import java.net.http.HttpClient;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -100,4 +101,25 @@ CompletableFuture<Optional<Collection<Language>>> getAvailableLanguages(
* Detection</a>
*/
CompletableFuture<Optional<DetectResponse>> detectLanguage(DetectLanguageParams params);

/**
* Gets the ratelimit manager.
*
* @return RateLimitManager - The ratelimit manager.
*/
RateLimitManager getRatelimitManager();

/**
* Gets the HttpClient.
*
* @return HttpClient - The HttpClient.
*/
HttpClient getHttpClient();

/**
* Gets the ObjectMapper.
*
* @return ObjectMapper - The ObjectMapper.
*/
ObjectMapper getObjectMapper();
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,6 @@ public AzureApi build() {
httpClient.connectTimeout(connectTimeout);
}

return new AzureApiImpl<>(httpClient.build(), baseURL, subscriptionKey, subscriptionRegion);
return new AzureApiImpl(httpClient.build(), baseURL, subscriptionKey, subscriptionRegion);
}
}
14 changes: 6 additions & 8 deletions src/main/java/io/github/brenoepics/at4j/core/AzureApiImpl.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package io.github.brenoepics.at4j.core;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.github.brenoepics.at4j.AzureApi;
import io.github.brenoepics.at4j.azure.BaseURL;
import io.github.brenoepics.at4j.azure.lang.Language;
import io.github.brenoepics.at4j.core.ratelimit.RateLimitManager;
import io.github.brenoepics.at4j.core.thread.ThreadPool;
import io.github.brenoepics.at4j.core.thread.ThreadPoolImpl;
import io.github.brenoepics.at4j.data.DetectedLanguage;
import io.github.brenoepics.at4j.data.request.AvailableLanguagesParams;
import io.github.brenoepics.at4j.data.request.DetectLanguageParams;
import io.github.brenoepics.at4j.data.request.TranslateParams;
Expand All @@ -18,9 +15,7 @@
import io.github.brenoepics.at4j.util.rest.RestEndpoint;
import io.github.brenoepics.at4j.util.rest.RestMethod;
import io.github.brenoepics.at4j.util.rest.RestRequest;

import java.net.http.HttpClient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
Expand All @@ -29,7 +24,7 @@
* This class is an implementation of the AzureApi interface. It provides methods to interact with
* Azure's translation API.
*/
public class AzureApiImpl<T> implements AzureApi {
public class AzureApiImpl implements AzureApi {

/** The Http Client for this instance. */
private final HttpClient httpClient;
Expand All @@ -47,7 +42,7 @@ public class AzureApiImpl<T> implements AzureApi {
private final ObjectMapper objectMapper = new ObjectMapper();

/** The ratelimit manager for this resource. */
private final RateLimitManager<T> ratelimitManager = new RateLimitManager<>(this);
private final RateLimitManager ratelimitManager = new RateLimitManager(this);

/** The thread pool which is used internally. */
private final ThreadPoolImpl threadPool = new ThreadPoolImpl();
Expand Down Expand Up @@ -143,6 +138,7 @@ public void disconnect() {
*
* @return HttpClient - The used HttpClient.
*/
@Override
public HttpClient getHttpClient() {
return this.httpClient;
}
Expand All @@ -152,6 +148,7 @@ public HttpClient getHttpClient() {
*
* @return ObjectMapper - The used ObjectMapper.
*/
@Override
public ObjectMapper getObjectMapper() {
return objectMapper;
}
Expand All @@ -161,7 +158,8 @@ public ObjectMapper getObjectMapper() {
*
* @return RateLimitManager - The used RateLimitManager.
*/
public RateLimitManager<T> getRatelimitManager() {
@Override
public RateLimitManager getRatelimitManager() {
return ratelimitManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* This class represents a rate limit bucket for Azure API requests. It manages the rate limit for
* each endpoint and major URL parameter combination.
*/
public class RateLimitBucket<T> {
public class RateLimitBucket<T, T4, T3> {

private final ConcurrentLinkedQueue<RestRequest<T>> requestQueue = new ConcurrentLinkedQueue<>();

Expand Down Expand Up @@ -103,7 +103,7 @@ public boolean endpointMatches(RestEndpoint endpoint) {
@Override
public boolean equals(Object obj) {
if (obj instanceof RateLimitBucket) {
RateLimitBucket<T> otherBucket = (RateLimitBucket<T>) obj;
RateLimitBucket<T, T4, T3> otherBucket = (RateLimitBucket) obj;
return endpointMatches(otherBucket.endpoint);
}
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.github.brenoepics.at4j.core.ratelimit;

import io.github.brenoepics.at4j.core.AzureApiImpl;
import io.github.brenoepics.at4j.AzureApi;
import io.github.brenoepics.at4j.core.exceptions.AzureException;
import io.github.brenoepics.at4j.util.logging.LoggerUtil;
import io.github.brenoepics.at4j.util.rest.RestRequest;
import io.github.brenoepics.at4j.util.rest.RestRequestHandler;
import io.github.brenoepics.at4j.util.rest.RestRequestResponseInfoImpl;
import io.github.brenoepics.at4j.util.rest.RestRequestResult;

import java.net.http.HttpHeaders;
import java.net.http.HttpResponse;
import java.util.HashSet;
Expand All @@ -16,20 +15,19 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

import org.apache.logging.log4j.Logger;

/** This class manages rate-limits and keeps track of them. */
public class RateLimitManager<T> {
public class RateLimitManager<T, T3, T4> {

/** The (logger) of this class. */
private static final Logger logger = LoggerUtil.getLogger(RateLimitManager.class);

/** The Azure API instance for this rate-limit manager. */
private final AzureApiImpl<T> api;
private final AzureApi api;

/** All buckets. */
private final Set<RateLimitBucket<T>> buckets = new HashSet<>();
private final Set<RateLimitBucket<T, T4, T3>> buckets = new HashSet<>();

/** The header for rate-limit remaining information. */
public static final String RATE_LIMITED_HEADER = "X-RateLimit-Remaining";
Expand All @@ -48,7 +46,7 @@ public class RateLimitManager<T> {
*
* @param api The azure api instance for this rate-limit manager.
*/
public RateLimitManager(AzureApiImpl<T> api) {
public RateLimitManager(AzureApi api) {
this.api = api;
}

Expand All @@ -59,7 +57,7 @@ public RateLimitManager(AzureApiImpl<T> api) {
* @param request The request to queue.
*/
public void queueRequest(RestRequest<T> request) {
Optional<RateLimitBucket<T>> searchBucket = searchBucket(request);
Optional<RateLimitBucket<T, T4, T3>> searchBucket = searchBucket(request);

if (searchBucket.isEmpty()) {
return;
Expand All @@ -73,7 +71,7 @@ public void queueRequest(RestRequest<T> request) {
*
* @param bucket The bucket to submit the request to.
*/
private void submitRequest(RateLimitBucket<T> bucket) {
private void submitRequest(RateLimitBucket<T, T4, T3> bucket) {
RestRequest<T> currentRequest = bucket.peekRequestFromQueue();
RestRequestResult<T> result = null;

Expand Down Expand Up @@ -101,7 +99,7 @@ private void submitRequest(RateLimitBucket<T> bucket) {
RestRequestHandler<T> handleCurrentRequest(
RestRequestResult<T> result,
RestRequest<T> currentRequest,
RateLimitBucket<T> bucket,
RateLimitBucket<T, T4, T3> bucket,
long responseTimestamp) {

try {
Expand Down Expand Up @@ -141,7 +139,7 @@ RestRequestHandler<T> handleCurrentRequest(
*
* @param bucket The bucket to wait for.
*/
void waitUntilSpaceGetsAvailable(RateLimitBucket<T> bucket) {
void waitUntilSpaceGetsAvailable(RateLimitBucket<T, T4, T3> bucket) {
int sleepTime = bucket.getTimeTillSpaceGetsAvailable();
if (sleepTime > 0) {
logger.debug(
Expand All @@ -166,7 +164,7 @@ void waitUntilSpaceGetsAvailable(RateLimitBucket<T> bucket) {
* @param bucket The bucket to retry the request for.
* @return The request that was retried.
*/
RestRequest<T> retryRequest(RateLimitBucket<T> bucket) {
RestRequest<T> retryRequest(RateLimitBucket<T, T4, T3> bucket) {
synchronized (buckets) {
bucket.pollRequestFromQueue();
RestRequest<T> request = bucket.peekRequestFromQueue();
Expand Down Expand Up @@ -199,9 +197,9 @@ private RestRequestResult<T> mapAzureException(Throwable t) {
* @param request The request.
* @return The bucket that fits to the request.
*/
Optional<RateLimitBucket<T>> searchBucket(RestRequest<T> request) {
Optional<RateLimitBucket<T, T4, T3>> searchBucket(RestRequest<T> request) {
synchronized (buckets) {
RateLimitBucket<T> bucket = getMatchingBucket(request);
RateLimitBucket<T, T4, T3> bucket = getMatchingBucket(request);

// Check if it is already in the queue, send not present
if (bucket.peekRequestFromQueue() != null) {
Expand All @@ -220,7 +218,7 @@ Optional<RateLimitBucket<T>> searchBucket(RestRequest<T> request) {
* @param request The request.
* @return The bucket that matches the request.
*/
RateLimitBucket<T> getMatchingBucket(RestRequest<T> request) {
RateLimitBucket<T, T4, T3> getMatchingBucket(RestRequest<?> request) {
synchronized (buckets) {
return buckets.stream()
.filter(b -> b.endpointMatches(request.getEndpoint()))
Expand All @@ -240,7 +238,7 @@ RateLimitBucket<T> getMatchingBucket(RestRequest<T> request) {
void handleResponse(
RestRequest<T> request,
RestRequestResult<T> result,
RateLimitBucket<T> bucket,
RateLimitBucket<T, T4, T3> bucket,
long responseTimestamp) {
try {
HttpResponse<String> response = result.getResponse();
Expand Down Expand Up @@ -279,7 +277,7 @@ void handleResponse(
* @param headers The headers of the response.
* @param bucket The bucket the request belongs to.
*/
private void handleCloudFlare(HttpHeaders headers, RateLimitBucket<T> bucket) {
private void handleCloudFlare(HttpHeaders headers, RateLimitBucket<T, T4, T3> bucket) {
logger.warn(
"Hit a CloudFlare API ban! {}",
"You were sending a very large amount of invalid requests.");
Expand All @@ -300,7 +298,7 @@ private void handleCloudFlare(HttpHeaders headers, RateLimitBucket<T> bucket) {
private void handleRateLimit(
CompletableFuture<RestRequestResult<T>> request,
RestRequestResult<T> result,
RateLimitBucket<T> bucket,
RateLimitBucket<T, T4, T3> bucket,
HttpHeaders headers) {

// Check if we didn't already complete it exceptionally.
Expand Down
31 changes: 11 additions & 20 deletions src/main/java/io/github/brenoepics/at4j/util/rest/RestRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import io.github.brenoepics.at4j.AT4J;
import io.github.brenoepics.at4j.AzureApi;
import io.github.brenoepics.at4j.core.AzureApiImpl;
import io.github.brenoepics.at4j.core.exceptions.AzureException;
import io.github.brenoepics.at4j.util.logging.LoggerUtil;
import java.io.IOException;
Expand All @@ -24,7 +23,7 @@ public class RestRequest<T> {
/** The (logger) of this class. */
private static final Logger logger = LoggerUtil.getLogger(RestRequest.class);

private final AzureApiImpl<T> api;
private final AzureApi api;
private final RestMethod method;
private final RestEndpoint endpoint;

Expand All @@ -39,7 +38,6 @@ public class RestRequest<T> {
private final Exception origin;

public static final String ERROR_FIELD = "error";
public static final String REFERENCE_LINK = AT4J.DOCS_URL + "error-reference/#azure-";

/**
* Creates a new instance of this class.
Expand All @@ -49,7 +47,7 @@ public class RestRequest<T> {
* @param endpoint The endpoint to which the request should be sent.
*/
public RestRequest(AzureApi api, RestMethod method, RestEndpoint endpoint) {
this.api = (AzureApiImpl) api;
this.api = api;
this.method = method;
this.endpoint = endpoint;
addQueryParameter("api-version", AT4J.AZURE_TRANSLATOR_API_VERSION);
Expand All @@ -67,7 +65,7 @@ public RestRequest(AzureApi api, RestMethod method, RestEndpoint endpoint) {
*/
public RestRequest(
AzureApi api, RestMethod method, RestEndpoint endpoint, boolean includeAuthorizationHeader) {
this.api = (AzureApiImpl) api;
this.api = api;
this.method = method;
this.endpoint = endpoint;
addQueryParameter("api-version", AT4J.AZURE_TRANSLATOR_API_VERSION);
Expand All @@ -81,7 +79,7 @@ public RestRequest(
*
* @return The api which is used for this request.
*/
public AzureApiImpl<T> getApi() {
public AzureApi getApi() {
return api;
}

Expand Down Expand Up @@ -133,36 +131,30 @@ public Exception getOrigin() {
/**
* Adds a query parameter to the url.
*
* @param key The key of the parameter.
* @param key The key of the parameter.
* @param value The value of the parameter.
* @return The current instance to chain call methods.
*/
public RestRequest<T> addQueryParameter(String key, String value) {
public void addQueryParameter(String key, String value) {
queryParameters.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
return this;
}

/**
* Adds multiple query parameters to the url.
*
* @param parameters The parameters to add.
* @return The current instance to chain call methods.
*/
public RestRequest<T> addQueryParameters(Map<String, String> parameters) {
public void addQueryParameters(Map<String, String> parameters) {
parameters.forEach(this::addQueryParameter);
return this;
}

/**
* Adds a header to the request.
*
* @param name The name of the header.
* @param name The name of the header.
* @param value The value of the header.
* @return The current instance to chain call methods.
*/
public RestRequest<T> addHeader(String name, String value) {
public void addHeader(String name, String value) {
headers.put(name, value);
return this;
}

public Map<String, String> getHeaders() {
Expand Down Expand Up @@ -194,11 +186,9 @@ public RestRequest<T> setBody(String body) {
* Sets if an authorization header should be included in this request.
*
* @param includeAuthorizationHeader Whether the authorization header should be included or not.
* @return The current instance to chain call methods.
*/
public RestRequest<T> includeAuthorizationHeader(boolean includeAuthorizationHeader) {
public void includeAuthorizationHeader(boolean includeAuthorizationHeader) {
this.includeAuthorizationHeader = includeAuthorizationHeader;
return this;
}

/**
Expand All @@ -207,6 +197,7 @@ public RestRequest<T> includeAuthorizationHeader(boolean includeAuthorizationHea
* @param function A function which processes the rest response to the requested object.
* @return A future which will contain the output of the function.
*/
@SuppressWarnings("unchecked")
public CompletableFuture<T> execute(Function<RestRequestResult<T>, T> function) {
api.getRatelimitManager().queueRequest(this);
CompletableFuture<T> future = new CompletableFuture<>();
Expand Down
Loading

0 comments on commit 9530643

Please sign in to comment.