Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: AEM-854: APIs are auto-closeable #105

Merged
merged 3 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@Path("/accounts-api/v2")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface AccountsApi
public interface AccountsApi extends AutoCloseable
{
/**
* Returns the list of projects for an account.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ <T> T build(
final T proxy = client.proxy(klass);
final RestApiExceptionHandler exceptionHandler = new RestApiExceptionHandler(exceptionMapper != null ? exceptionMapper : new DefaultRestApiExceptionMapper());
final ExceptionDecoratorInvocationHandler<T> handler = new ExceptionDecoratorInvocationHandler<>(proxy, exceptionHandler);
final CloseClientInvocationHandler closeClientInvocationHandler = new CloseClientInvocationHandler(handler, client.getResteasyClient());

return (T) Proxy.newProxyInstance(klass.getClassLoader(), new Class[] { klass }, handler);
return (T) Proxy.newProxyInstance(klass.getClassLoader(), new Class[] { klass }, closeClientInvocationHandler);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.smartling.api.v2.client;

import lombok.extern.slf4j.Slf4j;

import javax.ws.rs.client.Client;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
*
*/
@Slf4j
public class CloseClientInvocationHandler implements InvocationHandler
andy-radchenko marked this conversation as resolved.
Show resolved Hide resolved
{
private final InvocationHandler subhandler;
private final Client client;

CloseClientInvocationHandler(final InvocationHandler subhandler, Client client)
{
this.subhandler = subhandler;
this.client = client;
}

@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
{
if ("close".equals(method.getName()) && method.getParameterCount() == 0)
{
client.close();
return null;
}

return subhandler.invoke(proxy, method, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.smartling.api.v2.client;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import javax.ws.rs.client.Client;
import java.io.Closeable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class CloseClientInvocationHandlerTest
{
@Mock
private InvocationHandler subhandler;
@Mock
private Client client;
@InjectMocks
private CloseClientInvocationHandler testInstance;

@Before
public void setUp()
{
MockitoAnnotations.initMocks(this);
}

@Test
public void testSubhandlerCall() throws Throwable
{
when(subhandler.invoke(any(), any(), any())).thenReturn(2);

TestApi testApi = (TestApi)Proxy.newProxyInstance(TestApi.class.getClassLoader(), new Class[]{TestApi.class}, testInstance);
testApi.add(1);

verify(subhandler).invoke(any(), any(), any());
}

@Test
public void testClose() throws Throwable
{
TestApi testApi = (TestApi)Proxy.newProxyInstance(TestApi.class.getClassLoader(), new Class[]{TestApi.class}, testInstance);
testApi.close();

verify(client).close();
verify(subhandler, never()).invoke(any(), any(), any());
}

@Test
public void testCloseWithParam() throws Throwable
{
when(subhandler.invoke(any(), any(), any())).thenReturn(null);

TestApi testApi = (TestApi)Proxy.newProxyInstance(TestApi.class.getClassLoader(), new Class[]{TestApi.class}, testInstance);
testApi.close(1);

verify(subhandler).invoke(any(), any(), any());
verify(client, never()).close();
}

@Test
public void testCloseable() throws Exception
{
TestCloseableApi testApi = (TestCloseableApi)Proxy.newProxyInstance(TestCloseableApi.class.getClassLoader(), new Class[]{TestCloseableApi.class}, testInstance);
testApi.close();

verify(client).close();
}

@Test
public void testAutoCloseable() throws Exception
{
TestAutoCloseableApi testApi = (TestAutoCloseableApi)Proxy.newProxyInstance(TestAutoCloseableApi.class.getClassLoader(), new Class[]{TestAutoCloseableApi.class}, testInstance);
testApi.close();

verify(client).close();
}

private interface TestApi
{
int add(int a);
void close();
void close(int a);
}

private interface TestCloseableApi extends Closeable
{
int add(int a);
}

private interface TestAutoCloseableApi extends AutoCloseable
{
int add(int a);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@Path("/attachments-api/v2")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface AttachmentsApi
public interface AttachmentsApi extends AutoCloseable
{
@GET
@Path("/accounts/{accountUid}/{type}/{entityUid}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
@Path("/context-api/v2")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface ContextsApi
public interface ContextsApi extends AutoCloseable
{
@POST
@Path("/projects/{projectId}/contexts")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
@Path("/file-translations-api/v2")
public interface FileTranslationsApi
public interface FileTranslationsApi extends AutoCloseable
{
/**
* Upload file to perform further actions on it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
@Consumes(APPLICATION_JSON)
@Path("/files-api/v2")
@DetailedErrorMessage(args = "fileUri")
public interface FilesApi
public interface FilesApi extends AutoCloseable
{
@POST
@Path("/projects/{projectId}/file")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface GlossaryApi extends GlossaryManagementApi, EntryManagementApi, EntryAuthorizeForTranslationApi, ImportExportApi, LabelManagementApi {
public interface GlossaryApi extends GlossaryManagementApi, EntryManagementApi, EntryAuthorizeForTranslationApi, ImportExportApi, LabelManagementApi, AutoCloseable {

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface GlossaryManagementApi {
public interface GlossaryManagementApi extends AutoCloseable {
/**
* Read glossary.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface EntryManagementApi {
public interface EntryManagementApi extends AutoCloseable {
/**
* Read glossary entry.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface EntryAuthorizeForTranslationApi {
public interface EntryAuthorizeForTranslationApi extends AutoCloseable {

/**
* Allow to authorize entries for translation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface ImportExportApi {
public interface ImportExportApi extends AutoCloseable {
/**
* Export glossary - by filter.
* Caller of the method is responsible for closing the stream after reading its content.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
@Path("/glossary-api/v3")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface LabelManagementApi {
public interface LabelManagementApi extends AutoCloseable {

/**
* Read all labels that exists in scope of the account.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
@Path("/issues-api/v2")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface IssuesApi
public interface IssuesApi extends AutoCloseable
{
@GET
@Path("/dictionary/issue-states")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.smartling.api.v2.client.ClientFactory;
import com.smartling.api.v2.client.HttpClientConfiguration;
import com.smartling.api.v2.client.unmarshal.RestApiResponseReaderInterceptor;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;

Expand All @@ -15,22 +16,29 @@

public class FileUploadClientFactory extends ClientFactory
{
public ResteasyWebTarget build(List<ClientRequestFilter> clientRequestFilters, String domain, HttpClientConfiguration configuration)
public ResteasyClient build(HttpClientConfiguration configuration)
{
Objects.requireNonNull(configuration, "configuration must be defined");

ResteasyClientBuilder builder = ((ResteasyClientBuilder) ClientBuilder.newBuilder());
builder.httpEngine(super.getClientHttpEngine(configuration));

return builder.build();
}

public ResteasyWebTarget build(ResteasyClient resteasyClient, List<ClientRequestFilter> clientRequestFilters, String domain)
{
Objects.requireNonNull(resteasyClient, "resteasy client must be defined");
Objects.requireNonNull(clientRequestFilters, "clientRequestFilters must be defined");
Objects.requireNonNull(domain, "domain must be defined");
Objects.requireNonNull(configuration, "configuration must be defined");

if (!containsAuthFilter(clientRequestFilters))
{
throw new IllegalArgumentException("At least one request filter is required for authorization");
}

ResteasyClientBuilder builder = ((ResteasyClientBuilder) ClientBuilder.newBuilder());
builder.httpEngine(super.getClientHttpEngine(configuration));

ContextResolver<ObjectMapper> contextResolver = super.getObjectMapperContextResolver(super.getDeserializerMap(), super.getSerializerMap());
ResteasyWebTarget client = builder.build().target(domain).register(new RestApiResponseReaderInterceptor()).register(contextResolver);
ResteasyWebTarget client = resteasyClient.target(domain).register(new RestApiResponseReaderInterceptor()).register(contextResolver);

for (ClientRequestFilter filter : clientRequestFilters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.smartling.api.jobbatches.v1.pto.StreamFileUploadPTO;
import com.smartling.api.v2.response.ListResponse;
import lombok.extern.slf4j.Slf4j;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;

Expand All @@ -24,13 +25,15 @@
@Slf4j
public class FileUploadProxy implements JobBatchesApi
{
private JobBatchesApi delegate;
private ResteasyWebTarget client;
private final JobBatchesApi delegate;
private final ResteasyClient client;
private final ResteasyWebTarget target;

FileUploadProxy(JobBatchesApi delegate, ResteasyWebTarget client)
FileUploadProxy(JobBatchesApi delegate, ResteasyClient client, ResteasyWebTarget target)
{
this.delegate = delegate;
this.client = client;
this.target = target;
}

@Override
Expand Down Expand Up @@ -59,7 +62,7 @@ public void addFile(String projectId, String batchUid, FileUploadPTO fileUploadP
addClientLibIdIfNeeded(output);

String path = getPathAnnotationValue(JobBatchesApi.class, "addFile", String.class, String.class, FileUploadPTO.class);
Response response = sendRequest(client, path, projectId, batchUid, output);
Response response = sendRequest(target, path, projectId, batchUid, output);
releaseConnection(response);
}

Expand All @@ -71,7 +74,7 @@ public void addFileAsStream(String projectId, String batchUid, StreamFileUploadP
addClientLibIdIfNeeded(output);

String path = getPathAnnotationValue(JobBatchesApi.class, "addFileAsStream", String.class, String.class, StreamFileUploadPTO.class);
Response response = sendRequest(client, path, projectId, batchUid, output);
Response response = sendRequest(target, path, projectId, batchUid, output);
releaseConnection(response);
}

Expand All @@ -89,7 +92,7 @@ public void addFileAsync(String projectId, String batchUid, FileUploadPTO fileUp
addClientLibIdIfNeeded(output);

String path = getPathAnnotationValue(JobBatchesApi.class, "addFileAsync", String.class, String.class, FileUploadPTO.class);
Response response = sendRequest(client, path, projectId, batchUid, output);
Response response = sendRequest(target, path, projectId, batchUid, output);
releaseConnection(response);
}

Expand All @@ -101,7 +104,14 @@ public void addFileAsStreamAsync(String projectId, String batchUid, StreamFileUp
addClientLibIdIfNeeded(output);

String path = getPathAnnotationValue(JobBatchesApi.class, "addFileAsStreamAsync", String.class, String.class, StreamFileUploadPTO.class);
Response response = sendRequest(client, path, projectId, batchUid, output);
Response response = sendRequest(target, path, projectId, batchUid, output);
releaseConnection(response);
}

@Override
public void close() throws Exception
{
client.close();
delegate.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface JobBatchesApi
public interface JobBatchesApi extends AutoCloseable
{
@POST
@Path("job-batches-api/v1/projects/{projectId}/batches")
Expand Down
Loading
Loading