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 default handler overide , when user passed in interceptor should … #1609

Merged
merged 16 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -1,15 +1,22 @@
package com.microsoft.kiota.http;

import com.microsoft.kiota.RequestOption;
import com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider;
import com.microsoft.kiota.http.middleware.AuthorizationHandler;
import com.microsoft.kiota.http.middleware.HeadersInspectionHandler;
import com.microsoft.kiota.http.middleware.ParametersNameDecodingHandler;
import com.microsoft.kiota.http.middleware.RedirectHandler;
import com.microsoft.kiota.http.middleware.RetryHandler;
import com.microsoft.kiota.http.middleware.UrlReplaceHandler;
import com.microsoft.kiota.http.middleware.UserAgentHandler;
import com.microsoft.kiota.http.middleware.options.HeadersInspectionOption;
import com.microsoft.kiota.http.middleware.options.ParametersNameDecodingOption;
import com.microsoft.kiota.http.middleware.options.RedirectHandlerOption;
import com.microsoft.kiota.http.middleware.options.RetryHandlerOption;
import com.microsoft.kiota.http.middleware.options.UrlReplaceHandlerOption;
import com.microsoft.kiota.http.middleware.options.UserAgentHandlerOption;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
Expand All @@ -18,6 +25,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/** This class is used to build the HttpClient instance used by the core service. */
public class KiotaClientFactory {
Expand All @@ -31,12 +39,23 @@ private KiotaClientFactory() {}
return create(createDefaultInterceptors());
}

/**
* Creates an OkHttpClient Builder with the default configuration and middleware options.
* @param requestOptions The request options to use for the interceptors.
* @return an OkHttpClient Builder instance.
*/
@Nonnull public static OkHttpClient.Builder create(@Nonnull final RequestOption[] requestOptions) {
Objects.requireNonNull(requestOptions, "parameter requestOptions cannot be null");
return create(createDefaultInterceptors(requestOptions));
}

/**
* Creates an OkHttpClient Builder with the default configuration and middleware.
* @param interceptors The interceptors to add to the client. Will default to createDefaultInterceptors() if null.
* @return an OkHttpClient Builder instance.
*/
@Nonnull public static OkHttpClient.Builder create(@Nullable final Interceptor[] interceptors) {
@Nonnull public static OkHttpClient.Builder create(@Nonnull final Interceptor[] interceptors) {
Objects.requireNonNull(interceptors, "parameter interceptors cannot be null");
final OkHttpClient.Builder builder =
new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(100))
Expand All @@ -45,9 +64,7 @@ private KiotaClientFactory() {}
Duration.ofSeconds(
100)); // TODO configure the default client options.

final Interceptor[] interceptorsOrDefault =
interceptors != null ? interceptors : createDefaultInterceptors();
for (final Interceptor interceptor : interceptorsOrDefault) {
for (final Interceptor interceptor : interceptors) {
builder.addInterceptor(interceptor);
}
return builder;
Expand All @@ -58,12 +75,9 @@ private KiotaClientFactory() {}
* @param interceptors The interceptors to add to the client. Will default to createDefaultInterceptors() if null.
* @return an OkHttpClient Builder instance.
*/
@Nonnull public static OkHttpClient.Builder create(@Nullable final List<Interceptor> interceptors) {
if (interceptors == null) {
return create();
}
return create(
(new ArrayList<>(interceptors)).toArray(new Interceptor[interceptors.size()]));
@Nonnull public static OkHttpClient.Builder create(@Nonnull final List<Interceptor> interceptors) {
Objects.requireNonNull(interceptors, "parameter interceptors cannot be null");
return create((new ArrayList<>(interceptors)).toArray(new Interceptor[0]));
}

/**
Expand All @@ -73,7 +87,8 @@ private KiotaClientFactory() {}
*/
@Nonnull public static OkHttpClient.Builder create(
@Nonnull final BaseBearerTokenAuthenticationProvider authenticationProvider) {
ArrayList<Interceptor> interceptors = new ArrayList<>(createDefaultInterceptorsAsList());
ArrayList<Interceptor> interceptors =
new ArrayList<>(Arrays.asList(createDefaultInterceptors()));
interceptors.add(new AuthorizationHandler(authenticationProvider));
return create(interceptors);
}
Expand All @@ -83,19 +98,81 @@ private KiotaClientFactory() {}
* @return an array of interceptors.
*/
@Nonnull public static Interceptor[] createDefaultInterceptors() {
return new Interceptor[] {
new RedirectHandler(),
new RetryHandler(),
new ParametersNameDecodingHandler(),
new UserAgentHandler(),
new HeadersInspectionHandler()
};
return createDefaultInterceptors(new RequestOption[0]);
}

/**
* Creates the default interceptors for the client.
* @param requestOptions The request options to use for the interceptors.
* @return an array of interceptors.
*/
@Nonnull public static Interceptor[] createDefaultInterceptors(
@Nonnull final RequestOption[] requestOptions) {
Objects.requireNonNull(requestOptions, "parameter requestOptions cannot be null");

UrlReplaceHandlerOption uriReplacementOption = null;
baywet marked this conversation as resolved.
Show resolved Hide resolved
UserAgentHandlerOption userAgentHandlerOption = null;
RetryHandlerOption retryHandlerOption = null;
RedirectHandlerOption redirectHandlerOption = null;
ParametersNameDecodingOption parametersNameDecodingOption = null;
HeadersInspectionOption headersInspectionHandlerOption = null;

for (final RequestOption option : requestOptions) {
if (uriReplacementOption == null && option instanceof UrlReplaceHandlerOption) {
uriReplacementOption = (UrlReplaceHandlerOption) option;
} else if (retryHandlerOption == null && option instanceof RetryHandlerOption) {
retryHandlerOption = (RetryHandlerOption) option;
} else if (redirectHandlerOption == null && option instanceof RedirectHandlerOption) {
redirectHandlerOption = (RedirectHandlerOption) option;
} else if (parametersNameDecodingOption == null
&& option instanceof ParametersNameDecodingOption) {
parametersNameDecodingOption = (ParametersNameDecodingOption) option;
} else if (userAgentHandlerOption == null && option instanceof UserAgentHandlerOption) {
userAgentHandlerOption = (UserAgentHandlerOption) option;
} else if (headersInspectionHandlerOption == null
&& option instanceof HeadersInspectionOption) {
headersInspectionHandlerOption = (HeadersInspectionOption) option;
}
}

final List<Interceptor> handlers = new ArrayList<>();
// orders matter as they are executed in a chain
// interceptors that only modify the request should be added first
// interceptors that read the response should be added last
handlers.add(
userAgentHandlerOption != null
? new UserAgentHandler(userAgentHandlerOption)
: new UserAgentHandler());
handlers.add(
parametersNameDecodingOption != null
? new ParametersNameDecodingHandler(parametersNameDecodingOption)
: new ParametersNameDecodingHandler());
handlers.add(
uriReplacementOption != null
? new UrlReplaceHandler(uriReplacementOption)
: new UrlReplaceHandler());
handlers.add(
headersInspectionHandlerOption != null
? new HeadersInspectionHandler(headersInspectionHandlerOption)
: new HeadersInspectionHandler());
handlers.add(
redirectHandlerOption != null
? new RedirectHandler(redirectHandlerOption)
: new RedirectHandler());
handlers.add(
retryHandlerOption != null
? new RetryHandler(retryHandlerOption)
: new RetryHandler());

return handlers.toArray(new Interceptor[0]);
}

/**
* Creates the default interceptors for the client.
* @return an array of interceptors.
* @deprecated Use {@link #createDefaultInterceptors()} instead.
*/
@Deprecated
@Nonnull public static List<Interceptor> createDefaultInterceptorsAsList() {
return new ArrayList<>(Arrays.asList(createDefaultInterceptors()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.microsoft.kiota.http;

import static org.junit.jupiter.api.Assertions.*;

import com.microsoft.kiota.RequestOption;
import com.microsoft.kiota.http.middleware.ChaosHandler;
import com.microsoft.kiota.http.middleware.HeadersInspectionHandler;
import com.microsoft.kiota.http.middleware.ParametersNameDecodingHandler;
import com.microsoft.kiota.http.middleware.RedirectHandler;
import com.microsoft.kiota.http.middleware.RetryHandler;
import com.microsoft.kiota.http.middleware.UrlReplaceHandler;
import com.microsoft.kiota.http.middleware.UserAgentHandler;
import com.microsoft.kiota.http.middleware.options.RetryHandlerOption;
import com.microsoft.kiota.http.middleware.options.UrlReplaceHandlerOption;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class KiotaClientFactoryTest {

@Test
void testCreatesDefaultInterceptors() throws IOException {
OkHttpClient client = KiotaClientFactory.create().build();
assertNotNull(client.interceptors());
assertEquals(6, client.interceptors().size());
}

@Test
void testDefaultInterceptorsWhenPassedIn() throws IOException {
OkHttpClient client =
KiotaClientFactory.create(
new Interceptor[] {getDisabledRetryHandler(), new ChaosHandler()})
.build();
List<Interceptor> interceptors = client.interceptors();
assertNotNull(interceptors);
assertEquals(2, interceptors.size());
for (Interceptor interceptor : interceptors) {
if (interceptor instanceof RetryHandler) {
RetryHandlerOption handlerOption = ((RetryHandler) interceptor).getRetryOptions();
assertEquals(0, handlerOption.delay());
assertEquals(0, handlerOption.maxRetries());
}

assertTrue(
interceptor instanceof RetryHandler || interceptor instanceof ChaosHandler,
"Array should contain instances of RetryHandler and ChaosHandler");
}
}

@Test
void testDefaultInterceptorsWhenRequestOptionsPassedIn() throws IOException {
RetryHandlerOption retryHandlerOption =
new RetryHandlerOption((delay, executionCount, request, response) -> false, 0, 0);
UrlReplaceHandlerOption urlReplaceHandlerOption =
new UrlReplaceHandlerOption(new HashMap<>(), false);

final ArrayList<RequestOption> options = new ArrayList<>();
options.add(urlReplaceHandlerOption);
options.add(retryHandlerOption);

Interceptor[] interceptors =
KiotaClientFactory.createDefaultInterceptors(options.toArray(new RequestOption[0]));
OkHttpClient client = KiotaClientFactory.create(interceptors).build();
List<Interceptor> clientInterceptors = client.interceptors();
assertNotNull(interceptors);
assertEquals(6, clientInterceptors.size());
for (Interceptor interceptor : clientInterceptors) {
if (interceptor instanceof RetryHandler) {
RetryHandlerOption handlerOption = ((RetryHandler) interceptor).getRetryOptions();
assertEquals(0, handlerOption.delay());
assertEquals(0, handlerOption.maxRetries());
}

if (interceptor instanceof UrlReplaceHandler) {
UrlReplaceHandlerOption handlerOption =
((UrlReplaceHandler) interceptor).getUrlReplaceHandlerOption();
assertTrue(handlerOption.getReplacementPairs().isEmpty());
assertFalse(handlerOption.isEnabled());
}

assertTrue(
interceptor instanceof UrlReplaceHandler
|| interceptor instanceof RedirectHandler
|| interceptor instanceof RetryHandler
|| interceptor instanceof ParametersNameDecodingHandler
|| interceptor instanceof UserAgentHandler
|| interceptor instanceof HeadersInspectionHandler
|| interceptor instanceof ChaosHandler,
"Array should contain instances of"
+ " UrlReplaceHandler,RedirectHandler,RetryHandler,ParametersNameDecodingHandler,UserAgentHandler,"
+ " HeadersInspectionHandler, and ChaosHandler");
}
}

private static RetryHandler getDisabledRetryHandler() {
RetryHandlerOption retryHandlerOption =
new RetryHandlerOption((delay, executionCount, request, response) -> false, 0, 0);
RetryHandler retryHandler = new RetryHandler(retryHandlerOption);
return retryHandler;
}
}
Loading