Skip to content

Commit

Permalink
restrucuted internal clients composition
Browse files Browse the repository at this point in the history
  • Loading branch information
dili91 committed Oct 17, 2024
1 parent c7993df commit dcd2a0c
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 40 deletions.
4 changes: 3 additions & 1 deletion src/main/java/com/truelayer/java/TrueLayerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ public class TrueLayerClient implements ITrueLayerClient {
public TrueLayerClient(
IAuthenticationHandler authenticationHandler,
IHostedPaymentPageLinkBuilder hostedPaymentPageLinkBuilder,
ICommonHandler commonHandler) {
ICommonHandler commonHandler,
ISignupPlusHandler signupPlusHandler) {
this.authenticationHandler = authenticationHandler;
this.hostedPaymentPageLinkBuilder = hostedPaymentPageLinkBuilder;
this.commonHandler = commonHandler;
this.signupPlusHandler = signupPlusHandler;
}

/**
Expand Down
38 changes: 21 additions & 17 deletions src/main/java/com/truelayer/java/TrueLayerClientBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -221,30 +221,45 @@ public TrueLayerClient build() {
OkHttpClient baseHttpClient = httpClientFactory.buildBaseApiClient(
timeout, connectionPoolOptions, requestExecutor, logMessageConsumer, proxyConfiguration);

OkHttpClient authHttpClient = httpClientFactory.buildAuthApiClient(baseHttpClient, clientCredentials);
OkHttpClient authServerApiHttpClient =
httpClientFactory.buildAuthServerApiClient(baseHttpClient, clientCredentials);

IAuthenticationHandler authenticationHandler = AuthenticationHandler.New()
.clientCredentials(clientCredentials)
.httpClient(RetrofitFactory.build(authHttpClient, environment.getAuthApiUri()))
.httpClient(RetrofitFactory.build(authServerApiHttpClient, environment.getAuthApiUri()))
.build();

IHostedPaymentPageLinkBuilder hppLinkBuilder =
HostedPaymentPageLinkBuilder.New().uri(environment.getHppUri()).build();

// We're reusing a client with only User agent and Idempotency key interceptors and give it our base payment
// endpoint
ICommonApi commonApi = RetrofitFactory.build(authHttpClient, environment.getPaymentsApiUri())
ICommonApi commonApi = RetrofitFactory.build(authServerApiHttpClient, environment.getPaymentsApiUri())
.create(ICommonApi.class);
ICommonHandler commonHandler = new CommonHandler(commonApi);

// We're building a client which has the authentication handler and the options to cache the token.
// this one represents the baseline for the client used for Signup+ and Payments
OkHttpClient authenticatedApiClient = httpClientFactory.buildAuthenticatedApiClient(
authServerApiHttpClient, authenticationHandler, credentialsCache);
ISignupPlusApi signupPlusApi = RetrofitFactory.build(authenticatedApiClient, environment.getPaymentsApiUri())
.create(ISignupPlusApi.class);
SignupPlusHandler.SignupPlusHandlerBuilder signupPlusHandlerBuilder =
SignupPlusHandler.builder().signupPlusApi(signupPlusApi);
if (customScopesPresent()) {
signupPlusHandlerBuilder.scopes(globalScopes);
}
ISignupPlusHandler signupPlusHandler = signupPlusHandlerBuilder.build();

// As per our RFC, if signing options is not configured we create a client which is able to interact
// with the Authentication API only
if (isEmpty(signingOptions)) {
return new TrueLayerClient(authenticationHandler, hppLinkBuilder, commonHandler);
return new TrueLayerClient(authenticationHandler, hppLinkBuilder, commonHandler, signupPlusHandler);
}

OkHttpClient paymentsHttpClient = httpClientFactory.buildPaymentsApiClient(
authHttpClient, authenticationHandler, signingOptions, credentialsCache);
// The client used for PayIn endpoints has the authenticated as baseline, but adds the signature manager
OkHttpClient paymentsHttpClient =
httpClientFactory.buildPaymentsApiClient(authenticatedApiClient, signingOptions);

IPaymentsApi paymentsApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
.create(IPaymentsApi.class);
Expand Down Expand Up @@ -295,17 +310,6 @@ public TrueLayerClient build() {
}
IPayoutsHandler payoutsHandler = payoutsHandlerBuilder.build();

// We're reusing a client with only User agent and Idempotency key interceptors and give it our base payment
// endpoint
ISignupPlusApi signupPlusApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
.create(ISignupPlusApi.class);
SignupPlusHandler.SignupPlusHandlerBuilder signupPlusHandlerBuilder =
SignupPlusHandler.builder().signupPlusApi(signupPlusApi);
if (customScopesPresent()) {
signupPlusHandlerBuilder.scopes(globalScopes);
}
ISignupPlusHandler signupPlusHandler = signupPlusHandlerBuilder.build();

return new TrueLayerClient(
authenticationHandler,
paymentsHandler,
Expand Down
27 changes: 18 additions & 9 deletions src/main/java/com/truelayer/java/http/OkHttpClientFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public OkHttpClient buildBaseApiClient(
return clientBuilder.build();
}

public OkHttpClient buildAuthApiClient(OkHttpClient baseHttpClient, ClientCredentials clientCredentials) {
public OkHttpClient buildAuthServerApiClient(OkHttpClient baseHttpClient, ClientCredentials clientCredentials) {

if (isEmpty(clientCredentials)) {
throw new TrueLayerException("client credentials must be set");
Expand All @@ -107,17 +107,15 @@ public OkHttpClient buildAuthApiClient(OkHttpClient baseHttpClient, ClientCreden
return clientBuilder.build();
}

public OkHttpClient buildPaymentsApiClient(
OkHttpClient authApiHttpClient,
public OkHttpClient buildAuthenticatedApiClient(
OkHttpClient authServerApiClient,
IAuthenticationHandler authenticationHandler,
SigningOptions signingOptions,
ICredentialsCache credentialsCache) {

// By using .newBuilder() we share internal OkHttpClient resources
// we just need to add the signature and authentication interceptor
// as all the others are inherited
OkHttpClient.Builder paymentsHttpClientBuilder = authApiHttpClient.newBuilder();

paymentsHttpClientBuilder.addInterceptor(new SignatureGeneratorInterceptor(signingOptions));
OkHttpClient.Builder authenticatedApiClientBuilder = authServerApiClient.newBuilder();

AccessTokenManager.AccessTokenManagerBuilder accessTokenManagerBuilder =
AccessTokenManager.builder().authenticationHandler(authenticationHandler);
Expand All @@ -127,14 +125,25 @@ public OkHttpClient buildPaymentsApiClient(
AccessTokenManager accessTokenManager =
accessTokenManagerBuilder.credentialsCache(credentialsCache).build();

paymentsHttpClientBuilder
authenticatedApiClientBuilder
.addInterceptor(new AuthenticationInterceptor(accessTokenManager))
.authenticator(new AccessTokenInvalidator(accessTokenManager));
} else {
AccessTokenManager accessTokenManager = accessTokenManagerBuilder.build();
paymentsHttpClientBuilder.addInterceptor(new AuthenticationInterceptor(accessTokenManager));
authenticatedApiClientBuilder.addInterceptor(new AuthenticationInterceptor(accessTokenManager));
}

return authenticatedApiClientBuilder.build();
}

public OkHttpClient buildPaymentsApiClient(OkHttpClient authenticatedApiClient, SigningOptions signingOptions) {
// By using .newBuilder() we share internal OkHttpClient resources
// we just need to add the signature and authentication interceptor
// as all the others are inherited
OkHttpClient.Builder paymentsHttpClientBuilder = authenticatedApiClient.newBuilder();

paymentsHttpClientBuilder.addInterceptor(new SignatureGeneratorInterceptor(signingOptions));

return paymentsHttpClientBuilder.build();
}
}
53 changes: 40 additions & 13 deletions src/test/java/com/truelayer/java/http/OkHttpClientFactoryTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import com.truelayer.java.TestUtils;
import com.truelayer.java.auth.AuthenticationHandler;
import com.truelayer.java.auth.IAuthenticationHandler;
import com.truelayer.java.http.auth.cache.SimpleCredentialsCache;
import com.truelayer.java.http.interceptors.AuthenticationInterceptor;
import com.truelayer.java.http.interceptors.IdempotencyKeyGeneratorInterceptor;
import com.truelayer.java.http.interceptors.SignatureGeneratorInterceptor;
Expand All @@ -21,7 +20,6 @@
import com.truelayer.java.versioninfo.VersionInfo;
import java.net.Proxy;
import java.net.URI;
import java.time.Clock;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -181,7 +179,8 @@ public void shouldCreateAnAuthApiClient() {
customLogMessageConsumer,
null);

OkHttpClient authClient = getOkHttpClientFactory().buildAuthApiClient(baseApiClient, getClientCredentials());
OkHttpClient authClient =
getOkHttpClientFactory().buildAuthServerApiClient(baseApiClient, getClientCredentials());

assertNotNull(authClient);
assertTrue(
Expand All @@ -200,22 +199,50 @@ public void shouldCreateAnAuthApiClient() {
}

@Test
@DisplayName("It should build a Payments API client")
public void shouldThrowCredentialsMissingException() {
@DisplayName("It should build an authenticated API client")
public void shouldCreateAnAuthenticatedApiClient() {
OkHttpClient baseHttpClient = getOkHttpClientFactory().buildBaseApiClient(null, null, null, null, null);
OkHttpClient authClient = getOkHttpClientFactory().buildAuthApiClient(baseHttpClient, getClientCredentials());
OkHttpClient authServerApiClient =
getOkHttpClientFactory().buildAuthServerApiClient(baseHttpClient, getClientCredentials());
IAuthenticationHandler authenticationHandler = AuthenticationHandler.New()
.clientCredentials(getClientCredentials())
.httpClient(RetrofitFactory.build(baseHttpClient, URI.create("http://localhost")))
.build();

OkHttpClient authenticatedApiClient =
getOkHttpClientFactory().buildAuthenticatedApiClient(authServerApiClient, authenticationHandler, null);

assertNotNull(authenticatedApiClient);
assertTrue(
authenticatedApiClient.interceptors().stream()
.anyMatch(i -> i.getClass().equals(IdempotencyKeyGeneratorInterceptor.class)),
"Idempotency interceptor not found");
assertTrue(
authenticatedApiClient.interceptors().stream()
.anyMatch(i -> i.getClass().equals(TrueLayerAgentInterceptor.class)),
"User agent interceptor not found");
assertTrue(
authenticatedApiClient.interceptors().stream()
.anyMatch(i -> i.getClass().equals(AuthenticationInterceptor.class)),
"Authentication interceptor not found");
assertNotNull(authenticatedApiClient.authenticator());
}

@Test
@DisplayName("It should build a Payments API client")
public void shouldCreateAPaymentsApiClient() {
OkHttpClient baseHttpClient = getOkHttpClientFactory().buildBaseApiClient(null, null, null, null, null);
IAuthenticationHandler authenticationHandler = AuthenticationHandler.New()
.clientCredentials(getClientCredentials())
.httpClient(RetrofitFactory.build(authClient, URI.create("http://localhost")))
.httpClient(RetrofitFactory.build(baseHttpClient, URI.create("http://localhost")))
.build();
OkHttpClient authApiClient =
getOkHttpClientFactory().buildAuthServerApiClient(baseHttpClient, getClientCredentials());
OkHttpClient authenticatedApiClient =
getOkHttpClientFactory().buildAuthenticatedApiClient(authApiClient, authenticationHandler, null);

OkHttpClient paymentClient = getOkHttpClientFactory()
.buildPaymentsApiClient(
authClient,
authenticationHandler,
TestUtils.getSigningOptions(),
new SimpleCredentialsCache(Clock.systemUTC()));
OkHttpClient paymentClient =
getOkHttpClientFactory().buildPaymentsApiClient(authenticatedApiClient, TestUtils.getSigningOptions());

assertTrue(
paymentClient.interceptors().stream()
Expand Down

0 comments on commit dcd2a0c

Please sign in to comment.