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

TrueLayer / truelayer-java / #106

02 Jul 2025 08:28AM UTC coverage: 89.512%. First build
#106

Pull #336

github

web-flow
Merge branch 'main' into otel
Pull Request #336: Supports for OpenTelemetry

20 of 22 new or added lines in 2 files covered. (90.91%)

495 of 553 relevant lines covered (89.51%)

0.9 hits per line

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

78.26
/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.http.OkHttpClientFactory;
13
import com.truelayer.java.http.RetrofitFactory;
14
import com.truelayer.java.http.auth.cache.ICredentialsCache;
15
import com.truelayer.java.http.auth.cache.InMemoryCredentialsCache;
16
import com.truelayer.java.http.interceptors.logging.DefaultLogConsumer;
17
import com.truelayer.java.mandates.IMandatesApi;
18
import com.truelayer.java.mandates.IMandatesHandler;
19
import com.truelayer.java.mandates.MandatesHandler;
20
import com.truelayer.java.merchantaccounts.IMerchantAccountsApi;
21
import com.truelayer.java.merchantaccounts.IMerchantAccountsHandler;
22
import com.truelayer.java.merchantaccounts.MerchantAccountsHandler;
23
import com.truelayer.java.payments.IPaymentsApi;
24
import com.truelayer.java.payments.IPaymentsHandler;
25
import com.truelayer.java.payments.PaymentsHandler;
26
import com.truelayer.java.paymentsproviders.IPaymentsProvidersApi;
27
import com.truelayer.java.paymentsproviders.IPaymentsProvidersHandler;
28
import com.truelayer.java.paymentsproviders.PaymentsProvidersHandler;
29
import com.truelayer.java.payouts.IPayoutsApi;
30
import com.truelayer.java.payouts.IPayoutsHandler;
31
import com.truelayer.java.payouts.PayoutsHandler;
32
import com.truelayer.java.signupplus.ISignupPlusApi;
33
import com.truelayer.java.signupplus.ISignupPlusHandler;
34
import com.truelayer.java.signupplus.SignupPlusHandler;
35
import com.truelayer.java.versioninfo.LibraryInfoLoader;
36
import io.opentelemetry.api.OpenTelemetry;
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
    private OpenTelemetry openTelemetry = OpenTelemetry.noop();
1✔
83

84
    TrueLayerClientBuilder() {}
1✔
85

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

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

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

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

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

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

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

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

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

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

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

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

213
    public TrueLayerClientBuilder withOpenTelemetry(OpenTelemetry openTelemetry) {
NEW
214
        this.openTelemetry = openTelemetry;
×
NEW
215
        return this;
×
216
    }
217

218
    /**
219
     * Builds the Java library main class to interact with TrueLayer APIs.
220
     * @return a client instance
221
     * @see TrueLayerClient
222
     */
223
    public TrueLayerClient build() {
224
        if (isEmpty(clientCredentials)) {
1✔
225
            throw new TrueLayerException("client credentials must be set");
1✔
226
        }
227

228
        OkHttpClientFactory httpClientFactory = new OkHttpClientFactory(new LibraryInfoLoader());
1✔
229

230
        OkHttpClient baseHttpClient = httpClientFactory.buildBaseApiClient(
1✔
231
                timeout, connectionPoolOptions, requestExecutor, logMessageConsumer, proxyConfiguration);
232

233
        OkHttpClient authServerApiHttpClient =
1✔
234
                httpClientFactory.buildAuthServerApiClient(baseHttpClient, clientCredentials);
1✔
235

236
        IAuthenticationHandler authenticationHandler = AuthenticationHandler.New()
1✔
237
                .clientCredentials(clientCredentials)
1✔
238
                .httpClient(RetrofitFactory.build(authServerApiHttpClient, environment.getAuthApiUri(), openTelemetry))
1✔
239
                .build();
1✔
240

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

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

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

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

276
        IPaymentsApi paymentsApi = RetrofitFactory.build(
1✔
277
                        paymentsHttpClient, environment.getPaymentsApiUri(), openTelemetry)
1✔
278
                .create(IPaymentsApi.class);
1✔
279

280
        PaymentsHandler.PaymentsHandlerBuilder paymentsHandlerBuilder =
281
                PaymentsHandler.builder().paymentsApi(paymentsApi);
1✔
282
        if (customScopesPresent()) {
1✔
283
            paymentsHandlerBuilder.scopes(globalScopes);
×
284
        }
285
        IPaymentsHandler paymentsHandler = paymentsHandlerBuilder.build();
1✔
286

287
        IPaymentsProvidersApi paymentsProvidersApi = RetrofitFactory.build(
1✔
288
                        paymentsHttpClient, environment.getPaymentsApiUri(), openTelemetry)
1✔
289
                .create(IPaymentsProvidersApi.class);
1✔
290

291
        PaymentsProvidersHandler.PaymentsProvidersHandlerBuilder paymentsProvidersHandlerBuilder =
292
                PaymentsProvidersHandler.builder().paymentsProvidersApi(paymentsProvidersApi);
1✔
293
        if (customScopesPresent()) {
1✔
294
            paymentsProvidersHandlerBuilder.scopes(globalScopes);
×
295
        }
296
        IPaymentsProvidersHandler paymentsProvidersHandler = paymentsProvidersHandlerBuilder.build();
1✔
297

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

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

318
        IPayoutsApi payoutsApi = RetrofitFactory.build(
1✔
319
                        paymentsHttpClient, environment.getPaymentsApiUri(), openTelemetry)
1✔
320
                .create(IPayoutsApi.class);
1✔
321
        PayoutsHandler.PayoutsHandlerBuilder payoutsHandlerBuilder =
322
                PayoutsHandler.builder().payoutsApi(payoutsApi);
1✔
323
        if (customScopesPresent()) {
1✔
324
            merchantAccountsHandlerBuilder.scopes(globalScopes);
×
325
        }
326
        IPayoutsHandler payoutsHandler = payoutsHandlerBuilder.build();
1✔
327

328
        return new TrueLayerClient(
1✔
329
                authenticationHandler,
330
                paymentsHandler,
331
                paymentsProvidersHandler,
332
                merchantAccountsHandler,
333
                mandatesHandler,
334
                payoutsHandler,
335
                signupPlusHandler,
336
                commonHandler,
337
                new HostedPaymentPageLinkBuilder(environment));
338
    }
339

340
    private boolean customScopesPresent() {
341
        return isNotEmpty(globalScopes) && isNotEmpty(globalScopes.getScopes());
1✔
342
    }
343
}
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