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

smartsheet / smartsheet-java-sdk / #55

02 Oct 2024 07:40PM UTC coverage: 60.548% (+0.7%) from 59.836%
#55

push

github

web-flow
Release prep for 3.2.1 (#103)

4156 of 6864 relevant lines covered (60.55%)

0.61 hits per line

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

71.14
/src/main/java/com/smartsheet/api/internal/SmartsheetImpl.java
1
/*
2
 * Copyright (C) 2024 Smartsheet
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.smartsheet.api.internal;
18

19
import com.smartsheet.api.ContactResources;
20
import com.smartsheet.api.EventResources;
21
import com.smartsheet.api.FavoriteResources;
22
import com.smartsheet.api.FolderResources;
23
import com.smartsheet.api.GroupResources;
24
import com.smartsheet.api.HomeResources;
25
import com.smartsheet.api.ImageUrlResources;
26
import com.smartsheet.api.PassthroughResources;
27
import com.smartsheet.api.ReportResources;
28
import com.smartsheet.api.SearchResources;
29
import com.smartsheet.api.ServerInfoResources;
30
import com.smartsheet.api.SheetResources;
31
import com.smartsheet.api.SightResources;
32
import com.smartsheet.api.Smartsheet;
33
import com.smartsheet.api.TemplateResources;
34
import com.smartsheet.api.TokenResources;
35
import com.smartsheet.api.Trace;
36
import com.smartsheet.api.UserResources;
37
import com.smartsheet.api.WebhookResources;
38
import com.smartsheet.api.WorkspaceResources;
39
import com.smartsheet.api.internal.http.AndroidHttpClient;
40
import com.smartsheet.api.internal.http.DefaultHttpClient;
41
import com.smartsheet.api.internal.http.HttpClient;
42
import com.smartsheet.api.internal.json.JacksonJsonSerializer;
43
import com.smartsheet.api.internal.json.JsonSerializer;
44
import com.smartsheet.api.internal.util.CleanerUtil;
45
import com.smartsheet.api.internal.util.Util;
46
import org.apache.http.impl.client.HttpClients;
47

48
import java.io.IOException;
49
import java.net.URI;
50
import java.net.URL;
51
import java.util.Properties;
52
import java.util.concurrent.atomic.AtomicReference;
53

54
/**
55
 * This is the implementation of Smartsheet interface.
56
 * <p>
57
 * Thread Safety: This class is thread safe because all its mutable fields are safe-guarded using AtomicReference to
58
 * ensure atomic modifications, and also the underlying HttpClient and JsonSerializer interfaces are thread safe.
59
 */
60
public class SmartsheetImpl implements Smartsheet {
61

62
    /**
63
     * Represents the base URI of the Smartsheet REST API.
64
     * <p>
65
     * It will be initialized in constructor and will not change afterward.
66
     */
67
    private final URI baseURI;
68

69
    /**
70
     * Represents the AtomicReference for access token.
71
     * <p>
72
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
73
     * as null, and can be set via corresponding setter, therefore effectively the access token can be updated in the
74
     * SmartsheetImpl in thread safe manner.
75
     */
76
    private final AtomicReference<String> accessToken;
77

78
    /**
79
     * Represents the HttpClient.
80
     * <p>
81
     * It will be initialized in constructor and will not change afterward.
82
     */
83
    private final HttpClient httpClient;
84

85
    /**
86
     * Represents the JsonSerializer.
87
     * <p>
88
     * It will be initialized in constructor and will not change afterward.
89
     */
90
    private final JsonSerializer jsonSerializer;
91

92
    /**
93
     * Represents the AtomicReference for assumed user email.
94
     * <p>
95
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
96
     * as null, and can be set via corresponding setter, therefore effectively the assumed user can be updated in the
97
     * SmartsheetImpl in thread safe manner.
98
     */
99
    private final AtomicReference<String> assumedUser;
100

101
    /**
102
     * Represents the AtomicReference for change agent
103
     * <p>
104
     * It will be initialized in constructor and will not change afterward.
105
     */
106
    private final AtomicReference<String> changeAgent;
107

108
    /**
109
     * Represents the AtomicReference for the user agent
110
     */
111
    private final AtomicReference<String> userAgent;
112

113
    /**
114
     * Represents the AtomicReference to HomeResources.
115
     * <p>
116
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
117
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
118
     * effectively the underlying value is lazily created in a thread safe manner.
119
     */
120
    private final AtomicReference<HomeResources> home;
121

122
    /**
123
     * Represents the AtomicReference to WorkspaceResources.
124
     * <p>
125
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
126
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
127
     * effectively the underlying value is lazily created in a thread safe manner.
128
     */
129
    private final AtomicReference<WorkspaceResources> workspaces;
130

131
    /**
132
     * Represents the AtomicReference to FolderResources.
133
     * <p>
134
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
135
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
136
     * effectively the underlying value is lazily created in a thread safe manner.
137
     */
138
    private final AtomicReference<FolderResources> folders;
139

140
    /**
141
     * Represents the AtomicReference to TemplateResources.
142
     * <p>
143
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
144
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
145
     * effectively the underlying value is lazily created in a thread safe manner.
146
     */
147
    private final AtomicReference<TemplateResources> templates;
148

149
    /**
150
     * Represents the AtomicReference to SheetResources.
151
     * <p>
152
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
153
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
154
     * effectively the underlying value is lazily created in a thread safe manner.
155
     */
156
    private final AtomicReference<SheetResources> sheets;
157

158
    /**
159
     * Represents the AtomicReference to SightResources
160
     * <p>
161
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
162
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
163
     * effectively the underlying value is lazily created in a thread safe manner.
164
     */
165
    private final AtomicReference<SightResources> sights;
166

167
    /**
168
     * Represents the AtomicReference to UserResources.
169
     * <p>
170
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
171
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
172
     * effectively the underlying value is lazily created in a thread safe manner.
173
     */
174
    private final AtomicReference<UserResources> users;
175

176
    /**
177
     * Represents the AtomicReference to {@link GroupResources}.
178
     * <p>
179
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
180
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
181
     * effectively the underlying value is lazily created in a thread safe manner.
182
     */
183
    private final AtomicReference<GroupResources> groups;
184

185
    /**
186
     * Represents the AtomicReference to SearchResources.
187
     * <p>
188
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
189
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
190
     * effectively the underlying value is lazily created in a thread safe manner.
191
     */
192
    private final AtomicReference<SearchResources> search;
193

194
    /**
195
     * Represents the AtomicReference to ReportResources.
196
     * <p>
197
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
198
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
199
     * effectively the underlying value is lazily created in a thread safe manner.
200
     */
201
    private final AtomicReference<ReportResources> reports;
202

203
    /**
204
     * Represents the AtomicReference for ServerInfoResources.
205
     * <p>
206
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
207
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
208
     * effectively the underlying value is lazily created in a thread safe manner.
209
     */
210
    private final AtomicReference<ServerInfoResources> serverInfo;
211

212
    /**
213
     * Represents the AtomicReference for FavoriteResources.
214
     * <p>
215
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
216
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
217
     * effectively the underlying value is lazily created in a thread safe manner.
218
     */
219
    private final AtomicReference<FavoriteResources> favorites;
220

221
    /**
222
     * Represents the AtomicReference for TokenResources.
223
     * <p>
224
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
225
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
226
     * effectively the underlying value is lazily created in a thread safe manner.
227
     */
228
    private final AtomicReference<TokenResources> tokens;
229

230
    /**
231
     * Represents the AtomicReference for ContactResources.
232
     * <p>
233
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
234
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
235
     * effectively the underlying value is lazily created in a thread safe manner.
236
     */
237
    private final AtomicReference<ContactResources> contacts;
238

239
    /**
240
     * Represents the AtomicReference for ImageUrlResources.
241
     * <p>
242
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
243
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
244
     * effectively the underlying value is lazily created in a thread safe manner.
245
     */
246
    private final AtomicReference<ImageUrlResources> imageUrls;
247

248
    /**
249
     * Represents the AtomicReference for WebhookResources.
250
     * <p>
251
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
252
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
253
     * effectively the underlying value is lazily created in a thread safe manner.
254
     */
255
    private final AtomicReference<WebhookResources> webhooks;
256

257
    /**
258
     * Represents the AtomicReference for PassthroughResources.
259
     * <p>
260
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
261
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
262
     * effectively the underlying value is lazily created in a thread safe manner.
263
     */
264
    private final AtomicReference<PassthroughResources> passthrough;
265

266
    /**
267
     * Represents the AtomicReference for EventResources.
268
     * <p>
269
     * It will be initialized in constructor and will not change afterward. The underlying value will be initially set
270
     * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore
271
     * effectively the underlying value is lazily created in a thread safe manner.
272
     */
273
    private final AtomicReference<EventResources> events;
274

275
    private static final String INVALID_OPERATION_FOR_CLASS = "Invalid operation for class ";
276

277
    /**
278
     * Create an instance with given server URI, HttpClient (optional) and JsonSerializer (optional)
279
     * <p>
280
     * Exceptions: - IllegalArgumentException : if serverURI/version/accessToken is null/empty
281
     *
282
     * @param baseURI     the server uri
283
     * @param accessToken the access token
284
     */
285
    public SmartsheetImpl(String baseURI, String accessToken) {
286
        this(baseURI, accessToken, null, null);
×
287
    }
×
288

289
    /**
290
     * Create an instance with given server URI, HttpClient (optional) and JsonSerializer (optional)
291
     * <p>
292
     * Exceptions: - IllegalArgumentException : if serverURI/version/accessToken is null/empty
293
     *
294
     * @param baseURI        the server uri
295
     * @param accessToken    the access token
296
     * @param httpClient     the http client (optional)
297
     * @param jsonSerializer the json serializer (optional)
298
     */
299
    public SmartsheetImpl(String baseURI, String accessToken, HttpClient httpClient, JsonSerializer jsonSerializer) {
1✔
300
        Util.throwIfNull(baseURI);
1✔
301
        Util.throwIfEmpty(baseURI);
1✔
302

303
        this.baseURI = URI.create(baseURI);
1✔
304
        this.accessToken = new AtomicReference<>(accessToken);
1✔
305
        this.jsonSerializer = (jsonSerializer == null) ? new JacksonJsonSerializer() : jsonSerializer;
1✔
306
        this.httpClient = (httpClient == null)
1✔
307
                ? new DefaultHttpClient(HttpClients.createDefault(), this.jsonSerializer) : httpClient;
1✔
308
        CleanerUtil.register(this, CleanerUtil.closeQuietly(this.httpClient));
1✔
309

310
        this.assumedUser = new AtomicReference<>(null);
1✔
311
        this.changeAgent = new AtomicReference<>(null);
1✔
312
        this.userAgent = new AtomicReference<>(generateUserAgent(null));
1✔
313

314
        // Initialize resources
315
        this.home = new AtomicReference<>();
1✔
316
        this.workspaces = new AtomicReference<>();
1✔
317
        this.folders = new AtomicReference<>();
1✔
318
        this.templates = new AtomicReference<>();
1✔
319
        this.sheets = new AtomicReference<>();
1✔
320
        this.sights = new AtomicReference<>();
1✔
321
        this.favorites = new AtomicReference<>();
1✔
322
        this.users = new AtomicReference<>();
1✔
323
        this.groups = new AtomicReference<>();
1✔
324
        this.search = new AtomicReference<>();
1✔
325
        this.reports = new AtomicReference<>();
1✔
326
        this.serverInfo = new AtomicReference<>();
1✔
327
        this.tokens = new AtomicReference<>();
1✔
328
        this.contacts = new AtomicReference<>();
1✔
329
        this.imageUrls = new AtomicReference<>();
1✔
330
        this.webhooks = new AtomicReference<>();
1✔
331
        this.passthrough = new AtomicReference<>();
1✔
332
        this.events = new AtomicReference<>();
1✔
333
    }
1✔
334

335
    /**
336
     * Getter of corresponding field.
337
     * <p>
338
     * Returns: corresponding field.
339
     *
340
     * @return the base uri
341
     */
342
    URI getBaseURI() {
343
        return baseURI;
1✔
344
    }
345

346
    /**
347
     * Return the access token
348
     *
349
     * @return the access token
350
     */
351
    String getAccessToken() {
352
        return accessToken.get();
1✔
353
    }
354

355
    /**
356
     * Set the access token to use.
357
     * <p>
358
     * Parameters: - accessToken : the access token
359
     * <p>
360
     * Returns: None
361
     * <p>
362
     *
363
     * @param accessToken the new access token
364
     */
365
    public void setAccessToken(String accessToken) {
366
        this.accessToken.set(accessToken);
1✔
367
    }
1✔
368

369
    /**
370
     * Getter of corresponding field.
371
     *
372
     * @return corresponding field
373
     */
374
    JsonSerializer getJsonSerializer() {
375
        return jsonSerializer;
1✔
376
    }
377

378
    /**
379
     * Getter of corresponding field.
380
     *
381
     * @return corresponding field.
382
     */
383
    HttpClient getHttpClient() {
384
        return httpClient;
1✔
385
    }
386

387
    /**
388
     * Return the assumed user.
389
     *
390
     * @return the assumed user
391
     */
392
    String getAssumedUser() {
393
        return assumedUser.get();
1✔
394
    }
395

396
    /**
397
     * Set the email of the user to assume. Null/empty string indicates no user is assumed.
398
     *
399
     * @param assumedUser the email of the user to assume
400
     */
401
    public void setAssumedUser(String assumedUser) {
402
        this.assumedUser.set(assumedUser);
1✔
403
    }
1✔
404

405
    /**
406
     * Return the change agent identifier.
407
     *
408
     * @return the access token
409
     */
410
    String getChangeAgent() {
411
        return changeAgent.get();
1✔
412
    }
413

414
    /**
415
     * Sets the change agent identifier
416
     */
417
    public void setChangeAgent(String changeAgent) {
418
        this.changeAgent.set(changeAgent);
1✔
419
    }
1✔
420

421
    /**
422
     * Return the user agent string
423
     *
424
     * @return the user agent string
425
     */
426
    public String getUserAgent() {
427
        return userAgent.get();
1✔
428
    }
429

430
    /**
431
     * Sets the user agent string
432
     *
433
     * @param userAgent the user agent string
434
     */
435
    public void setUserAgent(String userAgent) {
436
        this.userAgent.set(generateUserAgent(userAgent));
×
437
    }
×
438

439
    /**
440
     * Sets the max retry time if the HttpClient is an instance of DefaultHttpClient
441
     *
442
     * @param maxRetryTimeMillis max retry time
443
     */
444
    public void setMaxRetryTimeMillis(long maxRetryTimeMillis) {
445
        if (this.httpClient instanceof DefaultHttpClient) {
×
446
            ((DefaultHttpClient) this.httpClient).setMaxRetryTimeMillis(maxRetryTimeMillis);
×
447
        } else if (this.httpClient instanceof AndroidHttpClient) {
×
448
            ((AndroidHttpClient) this.httpClient).setMaxRetryTimeMillis(maxRetryTimeMillis);
×
449
        } else {
450
            throw new UnsupportedOperationException(INVALID_OPERATION_FOR_CLASS + this.httpClient.getClass());
×
451
        }
452
    }
×
453

454
    /**
455
     * set what request/response fields to log in trace-logging
456
     */
457
    public void setTraces(Trace... traces) {
458
        if (this.httpClient instanceof DefaultHttpClient) {
1✔
459
            ((DefaultHttpClient) this.httpClient).setTraces(traces);
1✔
460
        } else {
461
            throw new UnsupportedOperationException(INVALID_OPERATION_FOR_CLASS + this.httpClient.getClass());
×
462
        }
463
    }
1✔
464

465
    /**
466
     * set whether or not to generate "pretty formatted" JSON in trace-logging
467
     */
468
    public void setTracePrettyPrint(boolean pretty) {
469
        if (this.httpClient instanceof DefaultHttpClient) {
×
470
            ((DefaultHttpClient) this.httpClient).setTracePrettyPrint(pretty);
×
471
        } else {
472
            throw new UnsupportedOperationException(INVALID_OPERATION_FOR_CLASS + this.httpClient.getClass());
×
473
        }
474
    }
×
475

476
    /**
477
     * Returns the HomeResources instance that provides access to Home resources.
478
     *
479
     * @return the home resources
480
     */
481
    public HomeResources homeResources() {
482
        if (home.get() == null) {
1✔
483
            home.compareAndSet(null, new HomeResourcesImpl(this));
1✔
484
        }
485
        return home.get();
1✔
486
    }
487

488
    /**
489
     * Returns the WorkspaceResources instance that provides access to Workspace resources.
490
     *
491
     * @return the workspace resources
492
     */
493
    public WorkspaceResources workspaceResources() {
494
        if (workspaces.get() == null) {
1✔
495
            workspaces.compareAndSet(null, new WorkspaceResourcesImpl(this));
1✔
496
        }
497
        return workspaces.get();
1✔
498
    }
499

500
    /**
501
     * Returns the FolderResources instance that provides access to Folder resources.
502
     *
503
     * @return the folder resources
504
     */
505
    public FolderResources folderResources() {
506
        if (folders.get() == null) {
1✔
507
            folders.compareAndSet(null, new FolderResourcesImpl(this));
1✔
508
        }
509
        return folders.get();
1✔
510
    }
511

512
    /**
513
     * Returns the TemplateResources instance that provides access to Template resources.
514
     *
515
     * @return the template resources
516
     */
517
    public TemplateResources templateResources() {
518
        if (templates.get() == null) {
1✔
519
            templates.compareAndSet(null, new TemplateResourcesImpl(this));
1✔
520
        }
521
        return templates.get();
1✔
522
    }
523

524
    /**
525
     * Returns the SheetResources instance that provides access to Sheet resources.
526
     *
527
     * @return the sheet resources
528
     */
529
    public SheetResources sheetResources() {
530
        if (sheets.get() == null) {
1✔
531
            sheets.compareAndSet(null, new SheetResourcesImpl(this));
1✔
532
        }
533
        return sheets.get();
1✔
534
    }
535

536
    /**
537
     * Returns the SightResources instance that provides access to Sight resources.
538
     *
539
     * @return the sight resources
540
     */
541
    public SightResources sightResources() {
542
        if (sights.get() == null) {
1✔
543
            sights.compareAndSet(null, new SightResourcesImpl(this));
1✔
544
        }
545
        return sights.get();
1✔
546
    }
547

548
    /**
549
     * Returns the FavoriteResources instance that provides access to Favorite resources.
550
     *
551
     * @return the favorite resources
552
     */
553
    public FavoriteResources favoriteResources() {
554
        if (favorites.get() == null) {
1✔
555
            favorites.compareAndSet(null, new FavoriteResourcesImpl(this));
1✔
556
        }
557
        return favorites.get();
1✔
558
    }
559

560
    /**
561
     * Returns the {@link UserResources} instance that provides access to User resources.
562
     *
563
     * @return the user resources
564
     */
565
    public UserResources userResources() {
566
        if (users.get() == null) {
1✔
567
            users.compareAndSet(null, new UserResourcesImpl(this));
1✔
568
        }
569
        return users.get();
1✔
570
    }
571

572
    /**
573
     * Returns the {@link GroupResources} instance that provides access to User resources.
574
     *
575
     * @return the user resources
576
     */
577
    public GroupResources groupResources() {
578
        if (groups.get() == null) {
×
579
            groups.compareAndSet(null, new GroupResourcesImpl(this));
×
580
        }
581
        return groups.get();
×
582
    }
583

584
    /**
585
     * Returns the {@link SearchResources} instance that provides access to searching resources.
586
     *
587
     * @return the search resources
588
     */
589
    public SearchResources searchResources() {
590
        if (search.get() == null) {
1✔
591
            search.compareAndSet(null, new SearchResourcesImpl(this));
1✔
592
        }
593
        return search.get();
1✔
594
    }
595

596
    /**
597
     * Returns the {@link ReportResources} instance that provides access to Report resources.
598
     *
599
     * @return the report resources
600
     */
601
    public ReportResources reportResources() {
602
        if (reports.get() == null) {
1✔
603
            reports.compareAndSet(null, new ReportResourcesImpl(this));
1✔
604
        }
605
        return reports.get();
1✔
606
    }
607

608
    /**
609
     * Returns the {@link ServerInfoResources} instance that provides access to ServerInfo resources.
610
     *
611
     * @return the ServerInfo resources
612
     */
613
    public ServerInfoResources serverInfoResources() {
614
        if (serverInfo.get() == null) {
×
615
            serverInfo.compareAndSet(null, new ServerInfoResourcesImpl(this));
×
616
        }
617
        return serverInfo.get();
×
618
    }
619

620
    /**
621
     * Returns the TokenResources instance that provides access to token resources.
622
     *
623
     * @return the token resources
624
     */
625
    public TokenResources tokenResources() {
626
        if (tokens.get() == null) {
×
627
            tokens.compareAndSet(null, new TokenResourcesImpl(this));
×
628
        }
629
        return tokens.get();
×
630
    }
631

632
    /**
633
     * Returns the ContactResources instance that provides access to contact resources.
634
     *
635
     * @return the contact resources
636
     */
637
    public ContactResources contactResources() {
638
        if (contacts.get() == null) {
×
639
            contacts.compareAndSet(null, new ContactResourcesImpl(this));
×
640
        }
641
        return contacts.get();
×
642
    }
643

644
    /**
645
     * Returns the ImageUrlResources instance that provides access to image url resources.
646
     *
647
     * @return the image url resources
648
     */
649
    public ImageUrlResources imageUrlResources() {
650
        if (imageUrls.get() == null) {
×
651
            imageUrls.compareAndSet(null, new ImageUrlResourcesImpl(this));
×
652
        }
653
        return imageUrls.get();
×
654
    }
655

656
    /**
657
     * Returns the WebhookResources instance that provides access to webhook resources.
658
     *
659
     * @return the webhook resources
660
     */
661
    public WebhookResources webhookResources() {
662
        if (webhooks.get() == null) {
×
663
            webhooks.compareAndSet(null, new WebhookResourcesImpl(this));
×
664
        }
665
        return webhooks.get();
×
666
    }
667

668
    /**
669
     * Returns the PassthroughResources instance that provides access to passthrough resources.
670
     *
671
     * @return the passthrough resources
672
     */
673
    public PassthroughResources passthroughResources() {
674
        if (passthrough.get() == null) {
×
675
            passthrough.compareAndSet(null, new PassthroughResourcesImpl(this));
×
676
        }
677
        return passthrough.get();
×
678
    }
679

680
    /**
681
     * Returns the EventResources instance that provides access to events resources.
682
     *
683
     * @return the events resources
684
     */
685
    public EventResources eventResources() {
686
        if (events.get() == null) {
×
687
            events.compareAndSet(null, new EventResourcesImpl(this));
×
688
        }
689
        return events.get();
×
690
    }
691

692
    /**
693
     * Compose a User-Agent string that represents this version of the SDK (along with platform info)
694
     *
695
     * @return a User-Agent string
696
     */
697
    private String generateUserAgent(String userAgent) {
698
        String title = null;
1✔
699
        String thisVersion = null;
1✔
700

701
        if (userAgent == null) {
1✔
702
            StackTraceElement[] callers = Thread.currentThread().getStackTrace();
1✔
703
            String module = null;
1✔
704
            String callerClass = null;
1✔
705
            int stackIdx;
706
            for (stackIdx = callers.length - 1; stackIdx >= 0; stackIdx--) {
1✔
707
                callerClass = callers[stackIdx].getClassName();
1✔
708
                try {
709
                    Class<?> clazz = Class.forName(callerClass);
1✔
710
                    ClassLoader classLoader = clazz.getClassLoader();
1✔
711
                    // skip JRE classes
712
                    if (classLoader == null) {
1✔
713
                        continue;
×
714
                    }
715
                    String classFilePath = callerClass.replace(".", "/") + ".class";
1✔
716
                    URL classUrl = classLoader.getResource(classFilePath);
1✔
717
                    if (classUrl != null) {
1✔
718
                        String classUrlPath = classUrl.getPath();
1✔
719
                        int jarSeparator = classUrlPath.indexOf('!');
1✔
720
                        if (jarSeparator > 0) {
1✔
721
                            module = classUrlPath.substring(0, jarSeparator);
1✔
722
                            // extract the last path element (the jar name only)
723
                            module = module.substring(module.lastIndexOf('/') + 1);
1✔
724
                            break;
1✔
725
                        }
726
                    }
727
                } catch (Exception ex) {
×
728
                    // Empty Catch Block
729
                }
×
730
            }
731
            userAgent = module + "!" + callerClass;
1✔
732
        }
733
        try {
734
            final Properties properties = new Properties();
1✔
735
            properties.load(this.getClass().getClassLoader().getResourceAsStream("sdk.properties"));
1✔
736
            thisVersion = properties.getProperty("sdk.version");
1✔
737
            title = properties.getProperty("sdk.name");
1✔
738
        } catch (IOException e) {
×
739
            // Empty Catch Block
740
        }
1✔
741
        return title + "/" + thisVersion + "/" + userAgent + "/" + System.getProperty("os.name") + " " +
1✔
742
                System.getProperty("java.vm.name") + " " + System.getProperty("java.vendor") + " " +
1✔
743
                System.getProperty("java.version");
1✔
744
    }
745
}
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