• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TrueLayer / truelayer-java / #102

14 Jan 2025 08:54AM UTC coverage: 89.662% (-0.2%) from 89.888%
#102

Pull #337

github

dili91
simplification
Pull Request #337: [ACL-263] Caching improvements

20 of 21 new or added lines in 5 files covered. (95.24%)

20 existing lines in 2 files now uncovered.

477 of 532 relevant lines covered (89.66%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.31
/src/main/java/com/truelayer/java/TrueLayerClientBuilder.java
1
package com.truelayer.java;
2

3
import static org.apache.commons.lang3.ObjectUtils.isEmpty;
4
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
5

6
import com.truelayer.java.auth.AuthenticationHandler;
7
import com.truelayer.java.auth.IAuthenticationHandler;
8
import com.truelayer.java.commonapi.CommonHandler;
9
import com.truelayer.java.commonapi.ICommonApi;
10
import com.truelayer.java.commonapi.ICommonHandler;
11
import com.truelayer.java.entities.RequestScopes;
12
import com.truelayer.java.hpp.IHostedPaymentPageLinkBuilder;
13
import com.truelayer.java.http.OkHttpClientFactory;
14
import com.truelayer.java.http.RetrofitFactory;
15
import com.truelayer.java.http.auth.cache.ICredentialsCache;
16
import com.truelayer.java.http.auth.cache.InMemoryCredentialsCache;
17
import com.truelayer.java.http.interceptors.logging.DefaultLogConsumer;
18
import com.truelayer.java.mandates.IMandatesApi;
19
import com.truelayer.java.mandates.IMandatesHandler;
20
import com.truelayer.java.mandates.MandatesHandler;
21
import com.truelayer.java.merchantaccounts.IMerchantAccountsApi;
22
import com.truelayer.java.merchantaccounts.IMerchantAccountsHandler;
23
import com.truelayer.java.merchantaccounts.MerchantAccountsHandler;
24
import com.truelayer.java.payments.IPaymentsApi;
25
import com.truelayer.java.payments.IPaymentsHandler;
26
import com.truelayer.java.payments.PaymentsHandler;
27
import com.truelayer.java.paymentsproviders.IPaymentsProvidersApi;
28
import com.truelayer.java.paymentsproviders.IPaymentsProvidersHandler;
29
import com.truelayer.java.paymentsproviders.PaymentsProvidersHandler;
30
import com.truelayer.java.payouts.IPayoutsApi;
31
import com.truelayer.java.payouts.IPayoutsHandler;
32
import com.truelayer.java.payouts.PayoutsHandler;
33
import com.truelayer.java.signupplus.ISignupPlusApi;
34
import com.truelayer.java.signupplus.ISignupPlusHandler;
35
import com.truelayer.java.signupplus.SignupPlusHandler;
36
import com.truelayer.java.versioninfo.LibraryInfoLoader;
37
import java.time.Clock;
38
import java.time.Duration;
39
import java.util.concurrent.ExecutorService;
40
import java.util.function.Consumer;
41
import okhttp3.OkHttpClient;
42

43
/**
44
 * Builder class for TrueLayerClient instances.
45
 */
46
public class TrueLayerClientBuilder {
47
    private ClientCredentials clientCredentials;
48

49
    private RequestScopes globalScopes;
50

51
    private SigningOptions signingOptions;
52

53
    /**
54
     * Optional timeout configuration that defines a time limit for a complete HTTP call.
55
     * This includes resolving DNS, connecting, writing the request body, server processing, as well as
56
     * reading the response body. If not set, the internal HTTP client configuration are used.
57
     */
58
    private Duration timeout;
59

60
    /**
61
     * Optional configuration for internal connection pool.
62
     */
63
    private ConnectionPoolOptions connectionPoolOptions;
64

65
    /**
66
     * Optional execution service to be used by the internal HTTP client.
67
     */
68
    private ExecutorService requestExecutor;
69

70
    // By default, production is used
71
    private Environment environment = Environment.live();
1✔
72

73
    private Consumer<String> logMessageConsumer;
74

75
    /**
76
     * Holder for the cache implementation. Null if caching is disabled
77
     */
78
    private ICredentialsCache credentialsCache;
79

80
    private ProxyConfiguration proxyConfiguration;
81

82
    TrueLayerClientBuilder() {}
1✔
83

84
    /**
85
     * Utility to set the client credentials required for Oauth2 protected endpoints.
86
     * @param credentials the credentials object that holds client id and secret.
87
     * @return the instance of the client builder used.
88
     * @see ClientCredentials
89
     */
90
    public TrueLayerClientBuilder clientCredentials(ClientCredentials credentials) {
91
        this.clientCredentials = credentials;
1✔
92
        return this;
1✔
93
    }
94

95
    /**
96
     * Utility to set the signing options required for payments.
97
     * @param signingOptions the signing options object that holds signature related information.
98
     * @return the instance of the client builder used.
99
     * @see SigningOptions
100
     */
101
    public TrueLayerClientBuilder signingOptions(SigningOptions signingOptions) {
102
        this.signingOptions = signingOptions;
1✔
103
        return this;
1✔
104
    }
105

106
    /**
107
     * Utility to set custom global scopes used by the library. If used, the specified scopes will override the
108
     * default scopes used by the library. If using this option, make sure to set valid scopes for all the API interactions
109
     * that your integration will have.
110
     * @param globalScopes custom global scopes to be used by the library for all authenticated endpoints.
111
     * @return the instance of the client builder used.
112
     */
113
    public TrueLayerClientBuilder withGlobalScopes(RequestScopes globalScopes) {
114
        this.globalScopes = globalScopes;
×
UNCOV
115
        return this;
×
116
    }
117

118
    /**
119
     * Utility to set a call timeout for the client.
120
     * @param timeout Optional timeout configuration that defines a time limit for a complete HTTP call.
121
     * This includes resolving DNS, connecting, writing the request body, server processing, as well as
122
     * reading the response body. If not set, the internal HTTP client configuration are used.
123
     * @return the instance of the client builder used.
124
     */
125
    public TrueLayerClientBuilder withTimeout(Duration timeout) {
126
        this.timeout = timeout;
×
UNCOV
127
        return this;
×
128
    }
129

130
    /**
131
     * Sets a connection pool for the internal HTTP client
132
     * @param connectionPoolOptions optional connection pool to be used
133
     * @return the instance of the client builder used.
134
     */
135
    public TrueLayerClientBuilder withConnectionPool(ConnectionPoolOptions connectionPoolOptions) {
136
        this.connectionPoolOptions = connectionPoolOptions;
×
UNCOV
137
        return this;
×
138
    }
139

140
    /**
141
     * Sets a custom HTTP request dispatcher for the internal HTTP client
142
     * @param requestExecutor an executor service responsible for handling the HTTP requests
143
     * @return the instance of the client builder used.
144
     */
145
    public TrueLayerClientBuilder withRequestExecutor(ExecutorService requestExecutor) {
146
        this.requestExecutor = requestExecutor;
×
UNCOV
147
        return this;
×
148
    }
149

150
    /**
151
     * Utility to configure the library to interact a specific <i>TrueLayer</i> environment.
152
     * By default, <i>TrueLayer</i> production environment is used.
153
     * @param environment the environment to use
154
     * @return the instance of the client builder used.
155
     * @see Environment
156
     */
157
    public TrueLayerClientBuilder environment(Environment environment) {
158
        this.environment = environment;
×
UNCOV
159
        return this;
×
160
    }
161

162
    /**
163
     * Utility to enable default logs for HTTP traces.
164
     * @return the instance of the client builder used
165
     */
166
    public TrueLayerClientBuilder withHttpLogs() {
167
        this.logMessageConsumer = new DefaultLogConsumer();
1✔
168
        return this;
1✔
169
    }
170

171
    /**
172
     * Utility to enable custom logging for HTTP traces. Please notice that blocking
173
     * in the context of this consumer invocation will affect performance. An asynchronous implementation is
174
     * strongly advised.
175
     * @param logConsumer a custom log consumer
176
     * @return the instance of the client builder used
177
     */
178
    public TrueLayerClientBuilder withHttpLogs(Consumer<String> logConsumer) {
179
        this.logMessageConsumer = logConsumer;
1✔
180
        return this;
1✔
181
    }
182

183
    /**
184
     * Utility to enable default in memory caching for Oauth credentials.
185
     * @return the instance of the client builder used
186
     */
187
    public TrueLayerClientBuilder withCredentialsCaching() {
188
        this.credentialsCache = new InMemoryCredentialsCache(Clock.systemUTC());
1✔
189
        return this;
1✔
190
    }
191

192
    /**
193
     * Utility to enable a custom cache for Oauth credentials.
194
     * @param credentialsCache the custom cache implementation
195
     * @return the instance of the client builder used
196
     */
197
    public TrueLayerClientBuilder withCredentialsCaching(ICredentialsCache credentialsCache) {
198
        this.credentialsCache = credentialsCache;
1✔
199
        return this;
1✔
200
    }
201

202
    /**
203
     * Utility to configure a custom proxy, optionally including an authentication.
204
     * @param proxyConfiguration the configuration describing the custom proxy
205
     * @return the instance of the client builder used
206
     */
207
    public TrueLayerClientBuilder withProxyConfiguration(ProxyConfiguration proxyConfiguration) {
208
        this.proxyConfiguration = proxyConfiguration;
×
UNCOV
209
        return this;
×
210
    }
211

212
    /**
213
     * Builds the Java library main class to interact with TrueLayer APIs.
214
     * @return a client instance
215
     * @see TrueLayerClient
216
     */
217
    public TrueLayerClient build() {
218
        if (isEmpty(clientCredentials)) {
1✔
219
            throw new TrueLayerException("client credentials must be set");
1✔
220
        }
221

222
        OkHttpClientFactory httpClientFactory = new OkHttpClientFactory(new LibraryInfoLoader());
1✔
223

224
        OkHttpClient baseHttpClient = httpClientFactory.buildBaseApiClient(
1✔
225
                timeout, connectionPoolOptions, requestExecutor, logMessageConsumer, proxyConfiguration);
226

227
        OkHttpClient authServerApiHttpClient =
1✔
228
                httpClientFactory.buildAuthServerApiClient(baseHttpClient, clientCredentials);
1✔
229

230
        IAuthenticationHandler authenticationHandler = AuthenticationHandler.New()
1✔
231
                .clientCredentials(clientCredentials)
1✔
232
                .httpClient(RetrofitFactory.build(authServerApiHttpClient, environment.getAuthApiUri()))
1✔
233
                .build();
1✔
234

235
        // TODO: shall we get rid of this now?
236
        IHostedPaymentPageLinkBuilder hppLinkBuilder = com.truelayer.java.hpp.HostedPaymentPageLinkBuilder.New()
1✔
237
                .uri(environment.getHppUri())
1✔
238
                .build();
1✔
239

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

246
        // We're building a client which has the authentication handler and the options to cache the token.
247
        // this one represents the baseline for the client used for Signup+ and Payments
248
        OkHttpClient authenticatedApiClient = httpClientFactory.buildAuthenticatedApiClient(
1✔
249
                clientCredentials.clientId, authServerApiHttpClient, authenticationHandler, credentialsCache);
250
        ISignupPlusApi signupPlusApi = RetrofitFactory.build(authenticatedApiClient, environment.getPaymentsApiUri())
1✔
251
                .create(ISignupPlusApi.class);
1✔
252
        SignupPlusHandler.SignupPlusHandlerBuilder signupPlusHandlerBuilder =
253
                SignupPlusHandler.builder().signupPlusApi(signupPlusApi);
1✔
254
        if (customScopesPresent()) {
1✔
UNCOV
255
            signupPlusHandlerBuilder.scopes(globalScopes);
×
256
        }
257
        ISignupPlusHandler signupPlusHandler = signupPlusHandlerBuilder.build();
1✔
258

259
        // As per our RFC, if signing options is not configured we create a client which is able to interact
260
        // with the Authentication API only
261
        if (isEmpty(signingOptions)) {
1✔
262
            return new TrueLayerClient(
1✔
263
                    authenticationHandler,
264
                    hppLinkBuilder,
265
                    commonHandler,
266
                    signupPlusHandler,
267
                    new HostedPaymentPageLinkBuilder(environment));
268
        }
269

270
        // The client used for PayIn endpoints has the authenticated as baseline, but adds the signature manager
271
        OkHttpClient paymentsHttpClient =
1✔
272
                httpClientFactory.buildPaymentsApiClient(authenticatedApiClient, signingOptions);
1✔
273

274
        IPaymentsApi paymentsApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
1✔
275
                .create(IPaymentsApi.class);
1✔
276

277
        PaymentsHandler.PaymentsHandlerBuilder paymentsHandlerBuilder =
278
                PaymentsHandler.builder().paymentsApi(paymentsApi);
1✔
279
        if (customScopesPresent()) {
1✔
UNCOV
280
            paymentsHandlerBuilder.scopes(globalScopes);
×
281
        }
282
        IPaymentsHandler paymentsHandler = paymentsHandlerBuilder.build();
1✔
283

284
        IPaymentsProvidersApi paymentsProvidersApi = RetrofitFactory.build(
1✔
285
                        paymentsHttpClient, environment.getPaymentsApiUri())
1✔
286
                .create(IPaymentsProvidersApi.class);
1✔
287

288
        PaymentsProvidersHandler.PaymentsProvidersHandlerBuilder paymentsProvidersHandlerBuilder =
289
                PaymentsProvidersHandler.builder().paymentsProvidersApi(paymentsProvidersApi);
1✔
290
        if (customScopesPresent()) {
1✔
UNCOV
291
            paymentsProvidersHandlerBuilder.scopes(globalScopes);
×
292
        }
293
        IPaymentsProvidersHandler paymentsProvidersHandler = paymentsProvidersHandlerBuilder.build();
1✔
294

295
        IMerchantAccountsApi merchantAccountsApi = RetrofitFactory.build(
1✔
296
                        paymentsHttpClient, environment.getPaymentsApiUri())
1✔
297
                .create(IMerchantAccountsApi.class);
1✔
298
        MerchantAccountsHandler.MerchantAccountsHandlerBuilder merchantAccountsHandlerBuilder =
299
                MerchantAccountsHandler.builder().merchantAccountsApi(merchantAccountsApi);
1✔
300
        if (customScopesPresent()) {
1✔
UNCOV
301
            merchantAccountsHandlerBuilder.scopes(globalScopes);
×
302
        }
303
        IMerchantAccountsHandler merchantAccountsHandler = merchantAccountsHandlerBuilder.build();
1✔
304

305
        IMandatesApi mandatesApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
1✔
306
                .create(IMandatesApi.class);
1✔
307
        MandatesHandler.MandatesHandlerBuilder mandatesHandlerBuilder =
308
                MandatesHandler.builder().mandatesApi(mandatesApi);
1✔
309
        if (customScopesPresent()) {
1✔
UNCOV
310
            mandatesHandlerBuilder.scopes(globalScopes);
×
311
        }
312
        IMandatesHandler mandatesHandler = mandatesHandlerBuilder.build();
1✔
313

314
        IPayoutsApi payoutsApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
1✔
315
                .create(IPayoutsApi.class);
1✔
316
        PayoutsHandler.PayoutsHandlerBuilder payoutsHandlerBuilder =
317
                PayoutsHandler.builder().payoutsApi(payoutsApi);
1✔
318
        if (customScopesPresent()) {
1✔
UNCOV
319
            merchantAccountsHandlerBuilder.scopes(globalScopes);
×
320
        }
321
        IPayoutsHandler payoutsHandler = payoutsHandlerBuilder.build();
1✔
322

323
        return new TrueLayerClient(
1✔
324
                authenticationHandler,
325
                paymentsHandler,
326
                paymentsProvidersHandler,
327
                merchantAccountsHandler,
328
                mandatesHandler,
329
                payoutsHandler,
330
                signupPlusHandler,
331
                commonHandler,
332
                hppLinkBuilder,
333
                new HostedPaymentPageLinkBuilder(environment));
334
    }
335

336
    private boolean customScopesPresent() {
337
        return isNotEmpty(globalScopes) && isNotEmpty(globalScopes.getScopes());
1✔
338
    }
339
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc