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

smartsheet / smartsheet-java-sdk / #60

24 Oct 2025 09:43AM UTC coverage: 60.156% (+0.4%) from 59.737%
#60

push

github

web-flow
Add Wiremock integration tests and update dependencies (#145)

* Add Wiremock integration tests and update dependencies

* Update test method names

* Bump version to 3.9.0 and address comments for the wiremock integration tests

* Refactor Wiremock integration tests for user resources to improve query parameter handling and update endpoint paths

* Fix imports

* Fix checkstyle errors

* Move wiremock tests to sdktest

* Remove redundant Wiremock tests from UserResourcesIT

* Remove unused imports from UserResourcesIT

* Revert UserResourcesIT

* Fix changelog

* Add copyright to WiremockTest

* Update wiremock base uri port

* Rename WiremockTest to UserResourcesContractTests for clarity

* Change WireMock default port

4392 of 7301 relevant lines covered (60.16%)

0.6 hits per line

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

71.43
/src/main/java/com/smartsheet/api/internal/AbstractResources.java
1
/*
2
 * Copyright (C) 2025 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.fasterxml.jackson.core.JsonParseException;
20
import com.fasterxml.jackson.databind.JsonMappingException;
21
import com.smartsheet.api.AuthorizationException;
22
import com.smartsheet.api.InvalidRequestException;
23
import com.smartsheet.api.ResourceNotFoundException;
24
import com.smartsheet.api.ServiceUnavailableException;
25
import com.smartsheet.api.SmartsheetException;
26
import com.smartsheet.api.SmartsheetRestException;
27
import com.smartsheet.api.internal.http.HttpEntity;
28
import com.smartsheet.api.internal.http.HttpMethod;
29
import com.smartsheet.api.internal.http.HttpRequest;
30
import com.smartsheet.api.internal.http.HttpResponse;
31
import com.smartsheet.api.internal.json.JSONSerializerException;
32
import com.smartsheet.api.internal.util.StreamUtil;
33
import com.smartsheet.api.internal.util.Util;
34
import com.fasterxml.jackson.databind.JsonDeserializer;
35
import com.smartsheet.api.models.Attachment;
36
import com.smartsheet.api.models.CopyOrMoveRowDirective;
37
import com.smartsheet.api.models.CopyOrMoveRowResult;
38
import com.smartsheet.api.models.PagedResult;
39
import com.smartsheet.api.models.Result;
40
import com.smartsheet.api.models.TokenPaginatedResult;
41
import com.smartsheet.api.models.ListAssetSharesResponse;
42
import org.apache.http.client.methods.CloseableHttpResponse;
43
import org.apache.http.client.methods.HttpPost;
44
import org.apache.http.entity.ContentType;
45
import org.apache.http.entity.mime.MultipartEntityBuilder;
46
import org.apache.http.impl.client.CloseableHttpClient;
47
import org.apache.http.impl.client.HttpClients;
48
import org.slf4j.Logger;
49
import org.slf4j.LoggerFactory;
50

51
import java.io.ByteArrayInputStream;
52
import java.io.ByteArrayOutputStream;
53
import java.io.IOException;
54
import java.io.InputStream;
55
import java.io.OutputStream;
56
import java.lang.reflect.InvocationTargetException;
57
import java.net.URI;
58
import java.net.URLEncoder;
59
import java.nio.charset.StandardCharsets;
60
import java.util.HashMap;
61
import java.util.List;
62
import java.util.Map;
63

64
/**
65
 * This is the base class of the Smartsheet REST API resources.
66
 * <p>
67
 * Thread Safety: This class is thread safe because it is immutable and the underlying SmartsheetImpl is thread safe.
68
 */
69
public abstract class AbstractResources {
70
    /**
71
     * this system property is used to control the number of characters logged from an API response in logs
72
     */
73
    public static final String PROPERTY_RESPONSE_LOG_CHARS = "Smartsheet.responseLogChars";
74

75
    private static final Logger log = LoggerFactory.getLogger(AbstractResources.class);
1✔
76

77
    /**
78
     * The Constant BUFFER_SIZE.
79
     */
80
    private static final int BUFFER_SIZE = 4098;
81

82
    private static final String JSON_CONTENT_TYPE = "application/json";
83
    private static final String HEADER_CONTENT_TYPE = "Content-Type";
84

85
    /**
86
     * The Enum ErrorCode.
87
     */
88
    public enum ErrorCode {
1✔
89
        BAD_REQUEST(400, InvalidRequestException.class),
1✔
90
        NOT_AUTHORIZED(401, AuthorizationException.class),
1✔
91
        FORBIDDEN(403, AuthorizationException.class),
1✔
92
        NOT_FOUND(404, ResourceNotFoundException.class),
1✔
93
        METHOD_NOT_SUPPORTED(405, InvalidRequestException.class),
1✔
94
        INTERNAL_SERVER_ERROR(500, InvalidRequestException.class),
1✔
95
        SERVICE_UNAVAILABLE(503, ServiceUnavailableException.class);
1✔
96

97
        /**
98
         * The error code.
99
         */
100
        int errorCode;
101

102
        /**
103
         * The Exception class.
104
         */
105
        Class<? extends SmartsheetRestException> exceptionClass;
106

107
        /**
108
         * Instantiates a new error code.
109
         *
110
         * @param errorCode      the error code
111
         * @param exceptionClass the Exception class
112
         */
113
        ErrorCode(int errorCode, Class<? extends SmartsheetRestException> exceptionClass) {
1✔
114
            this.errorCode = errorCode;
1✔
115
            this.exceptionClass = exceptionClass;
1✔
116
        }
1✔
117

118
        /**
119
         * Gets the error code.
120
         *
121
         * @param errorNumber the error number
122
         * @return the error code
123
         */
124
        public static ErrorCode getErrorCode(int errorNumber) {
125
            for (ErrorCode code : ErrorCode.values()) {
1✔
126
                if (code.errorCode == errorNumber) {
1✔
127
                    return code;
1✔
128
                }
129
            }
130

131
            return null;
×
132
        }
133

134
        /**
135
         * Gets the exception.
136
         *
137
         * @return the exception
138
         * @throws InstantiationException the instantiation exception
139
         * @throws IllegalAccessException the illegal access exception
140
         */
141
        public SmartsheetRestException getException() throws InstantiationException, IllegalAccessException {
142
            return exceptionClass.newInstance();
×
143
        }
144

145
        /**
146
         * Gets the exception.
147
         *
148
         * @param error the error
149
         * @return the exception
150
         * @throws SmartsheetException the smartsheet exception
151
         */
152
        public SmartsheetRestException getException(com.smartsheet.api.models.Error error) throws SmartsheetException {
153

154
            try {
155
                return exceptionClass.getConstructor(com.smartsheet.api.models.Error.class).newInstance(error);
1✔
156
            } catch (IllegalArgumentException e) {
×
157
                throw new SmartsheetException(e);
×
158
            } catch (SecurityException e) {
×
159
                throw new SmartsheetException(e);
×
160
            } catch (InstantiationException e) {
×
161
                throw new SmartsheetException(e);
×
162
            } catch (IllegalAccessException e) {
×
163
                throw new SmartsheetException(e);
×
164
            } catch (InvocationTargetException e) {
×
165
                throw new SmartsheetException(e);
×
166
            } catch (NoSuchMethodException e) {
×
167
                throw new SmartsheetException(e);
×
168
            }
169
        }
170
    }
171

172
    /**
173
     * Represents the SmartsheetImpl.
174
     * <p>
175
     * It will be initialized in constructor and will not change afterwards.
176
     */
177
    protected final SmartsheetImpl smartsheet;
178

179
    /**
180
     * Constructor.
181
     *
182
     * @param smartsheet the smartsheet
183
     */
184
    protected AbstractResources(SmartsheetImpl smartsheet) {
1✔
185
        Util.throwIfNull(smartsheet);
1✔
186

187
        this.smartsheet = smartsheet;
1✔
188
    }
1✔
189

190
    /**
191
     * Get a resource from Smartsheet REST API.
192
     * <p>
193
     * Parameters: - path : the relative path of the resource - objectClass : the resource object class
194
     * <p>
195
     * Returns: the resource (note that if there is no such resource, this method will throw ResourceNotFoundException
196
     * rather than returning null).
197
     * <p>
198
     * Exceptions: -
199
     * InvalidRequestException : if there is any problem with the REST API request
200
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
201
     * ResourceNotFoundException : if the resource can not be found
202
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
203
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
204
     * SmartsheetException : if there is any other error occurred during the operation
205
     *
206
     * @param <T>         the generic type
207
     * @param path        the relative path of the resource.
208
     * @param objectClass the object class
209
     * @return the resource
210
     * @throws SmartsheetException the smartsheet exception
211
     */
212
    protected <T> T getResource(String path, Class<T> objectClass) throws SmartsheetException {
213
        Util.throwIfNull(path, objectClass);
1✔
214

215
        if (path.isEmpty()) {
1✔
216
            com.smartsheet.api.models.Error error = new com.smartsheet.api.models.Error();
×
217
            error.setMessage("An empty path was provided.");
×
218
            throw new ResourceNotFoundException(error);
×
219
        }
220

221
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
1✔
222

223
        T obj = null;
1✔
224
        String content = null;
1✔
225
        try {
226
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
227
            InputStream inputStream = response.getEntity().getContent();
1✔
228
            switch (response.getStatusCode()) {
1✔
229
                case 200:
230
                    try {
231
                        if (log.isInfoEnabled()) {
1✔
232
                            ByteArrayOutputStream contentCopyStream = new ByteArrayOutputStream();
×
233
                            inputStream = StreamUtil.cloneContent(inputStream, response.getEntity().getContentLength(), contentCopyStream);
×
234
                            content = StreamUtil.toUtf8StringOrHex(contentCopyStream, getResponseLogLength());
×
235
                        }
236
                        obj = this.smartsheet.getJsonSerializer().deserialize(objectClass, inputStream);
1✔
237
                    } catch (JsonParseException e) {
×
238
                        log.info("failure parsing '{}'", content, e);
×
239
                        throw new SmartsheetException(e);
×
240
                    } catch (JsonMappingException e) {
×
241
                        log.info("failure mapping '{}'", content, e);
×
242
                        throw new SmartsheetException(e);
×
243
                    } catch (IOException e) {
×
244
                        log.info("failure loading '{}'", content, e);
×
245
                        throw new SmartsheetException(e);
×
246
                    }
1✔
247
                    break;
248
                default:
249
                    handleError(response);
×
250
            }
251
        } catch (JSONSerializerException jsx) {
×
252
            log.info("failed to parse '{}'", content, jsx);
×
253
            throw jsx;
×
254
        } finally {
255
            smartsheet.getHttpClient().releaseConnection();
1✔
256
        }
257
        return obj;
1✔
258
    }
259

260
    /**
261
     * Create a resource using Smartsheet REST API.
262
     * <p>
263
     * Exceptions:
264
     * IllegalArgumentException : if any argument is null, or path is empty string
265
     * InvalidRequestException : if there is any problem with the REST API request
266
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
267
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
268
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
269
     * SmartsheetException : if there is any other error occurred during the operation
270
     *
271
     * @param <T>         the generic type of object to return/deserialize
272
     * @param <S>         the generic type of object to serialize
273
     * @param path        the relative path of the resource collections
274
     * @param objectClass the resource object class
275
     * @param object      the object to create
276
     * @return the created resource
277
     * @throws SmartsheetException the smartsheet exception
278
     */
279
    protected <T, S> T createResource(String path, Class<T> objectClass, S object) throws SmartsheetException {
280
        Util.throwIfNull(path, object, objectClass);
1✔
281
        Util.throwIfEmpty(path);
1✔
282

283
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.POST);
1✔
284

285
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
286
        this.smartsheet.getJsonSerializer().serialize(object, objectBytesStream);
1✔
287
        HttpEntity entity = new HttpEntity();
1✔
288
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
289
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
290
        entity.setContentLength(objectBytesStream.size());
1✔
291
        request.setEntity(entity);
1✔
292

293
        T obj = null;
1✔
294
        try {
295
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
296
            switch (response.getStatusCode()) {
1✔
297
                case 200: {
298
                    InputStream inputStream = response.getEntity().getContent();
1✔
299
                    String content = null;
1✔
300
                    try {
301
                        if (log.isInfoEnabled()) {
1✔
302
                            ByteArrayOutputStream contentCopyStream = new ByteArrayOutputStream();
×
303
                            inputStream = StreamUtil.cloneContent(inputStream, response.getEntity().getContentLength(), contentCopyStream);
×
304
                            content = StreamUtil.toUtf8StringOrHex(contentCopyStream, getResponseLogLength());
×
305
                        }
306
                        obj = this.smartsheet.getJsonSerializer().deserializeResult(objectClass, inputStream).getResult();
1✔
307
                    } catch (JSONSerializerException e) {
×
308
                        log.info("failure parsing '{}'", content, e);
×
309
                        throw new SmartsheetException(e);
×
310
                    } catch (IOException e) {
×
311
                        log.info("failure cloning content from inputStream '{}'", inputStream, e);
×
312
                        throw new SmartsheetException(e);
×
313
                    }
1✔
314
                    break;
315
                }
316
                default:
317
                    handleError(response);
×
318
            }
319
        } finally {
320
            smartsheet.getHttpClient().releaseConnection();
1✔
321
        }
322

323
        return obj;
1✔
324
    }
325

326
    /**
327
     * Create a resource using Smartsheet REST API.
328
     * <p>
329
     * Exceptions:
330
     * IllegalArgumentException : if any argument is null, or path is empty string
331
     * InvalidRequestException : if there is any problem with the REST API request
332
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
333
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
334
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
335
     * SmartsheetException : if there is any other error occurred during the operation
336
     *
337
     * @param <T>         the generic type
338
     * @param path        the relative path of the resource collections
339
     * @param objectClass the resource object class
340
     * @param object      the object to create
341
     * @return the created resource
342
     * @throws SmartsheetException the smartsheet exception
343
     */
344
    protected <T> T createResourceWithAttachment(
345
            String path,
346
            Class<T> objectClass,
347
            T object,
348
            String partName,
349
            InputStream inputStream,
350
            String contentType,
351
            String attachmentName
352
    ) throws SmartsheetException {
353
        Util.throwIfNull(path, object);
1✔
354
        Util.throwIfEmpty(path);
1✔
355

356
        HttpRequest request;
357
        final String boundary = "----" + System.currentTimeMillis();
1✔
358
        CloseableHttpClient httpClient = HttpClients.createDefault();
1✔
359
        HttpPost uploadFile = createHttpPost(this.getSmartsheet().getBaseURI().resolve(path));
1✔
360

361
        try {
362
            uploadFile.setHeader(HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
1✔
363
        } catch (Exception e) {
×
364
            throw new RuntimeException(e);
×
365
        }
1✔
366

367
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
1✔
368
        builder.setBoundary(boundary);
1✔
369
        builder.addTextBody(partName, this.getSmartsheet().getJsonSerializer().serialize(object), ContentType.APPLICATION_JSON);
1✔
370
        builder.addBinaryBody("file", inputStream, ContentType.create(contentType), attachmentName);
1✔
371
        org.apache.http.HttpEntity multipart = builder.build();
1✔
372

373
        uploadFile.setEntity(multipart);
1✔
374

375
        T obj = null;
1✔
376
        //implement switch case
377
        try {
378
            CloseableHttpResponse response = httpClient.execute(uploadFile);
1✔
379
            org.apache.http.HttpEntity responseEntity = response.getEntity();
1✔
380
            obj = this.getSmartsheet().getJsonSerializer().deserializeResult(objectClass,
1✔
381
                    responseEntity.getContent()).getResult();
1✔
382
        } catch (Exception e) {
×
383
            throw new RuntimeException(e);
×
384
        }
1✔
385
        return obj;
1✔
386
    }
387

388
    /**
389
     * Update a resource using Smartsheet REST API.
390
     * <p>
391
     * Exceptions:
392
     * IllegalArgumentException : if any argument is null, or path is empty string
393
     * InvalidRequestException : if there is any problem with the REST API request
394
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
395
     * ResourceNotFoundException : if the resource can not be found
396
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
397
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
398
     * SmartsheetException : if there is any other error occurred during the operation
399
     *
400
     * @param <T>         the generic type
401
     * @param path        the relative path of the resource
402
     * @param objectClass the resource object class
403
     * @param object      the object to create
404
     * @return the updated resource
405
     * @throws SmartsheetException the smartsheet exception
406
     */
407
    protected <T> T updateResource(String path, Class<T> objectClass, T object) throws SmartsheetException {
408
        Util.throwIfNull(path, object);
1✔
409
        Util.throwIfEmpty(path);
1✔
410

411
        HttpRequest request;
412
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.PUT);
1✔
413

414
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
415
        this.smartsheet.getJsonSerializer().serialize(object, objectBytesStream);
1✔
416
        HttpEntity entity = new HttpEntity();
1✔
417
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
418
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
419
        entity.setContentLength(objectBytesStream.size());
1✔
420
        request.setEntity(entity);
1✔
421

422
        T obj = null;
1✔
423
        try {
424
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
425
            switch (response.getStatusCode()) {
1✔
426
                case 200:
427
                    obj = this.smartsheet.getJsonSerializer().deserializeResult(objectClass,
1✔
428
                            response.getEntity().getContent()).getResult();
1✔
429
                    break;
1✔
430
                default:
431
                    handleError(response);
×
432
            }
433
        } finally {
434
            smartsheet.getHttpClient().releaseConnection();
1✔
435
        }
436

437
        return obj;
1✔
438
    }
439

440
    /**
441
     * List resources using Smartsheet REST API.
442
     * <p>
443
     * Exceptions:
444
     * IllegalArgumentException : if any argument is null, or path is empty string
445
     * InvalidRequestException : if there is any problem with the REST API request
446
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
447
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
448
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
449
     * SmartsheetException : if there is any other error occurred during the operation
450
     *
451
     * @param <T>         the generic type
452
     * @param path        the relative path of the resource collections
453
     * @param objectClass the resource object class
454
     * @return the resources
455
     * @throws SmartsheetException if an error occurred during the operation
456
     */
457
    protected <T> List<T> listResources(String path, Class<T> objectClass) throws SmartsheetException {
458
        Util.throwIfNull(path, objectClass);
×
459
        Util.throwIfEmpty(path);
×
460

461
        HttpRequest request;
462
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
×
463

464
        List<T> obj = null;
×
465
        try {
466
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
×
467
            switch (response.getStatusCode()) {
×
468
                case 200:
469
                    obj = this.smartsheet.getJsonSerializer().deserializeList(objectClass,
×
470
                            response.getEntity().getContent());
×
471
                    break;
×
472
                default:
473
                    handleError(response);
×
474
            }
475
        } finally {
476
            smartsheet.getHttpClient().releaseConnection();
×
477
        }
478

479
        return obj;
×
480
    }
481

482
    /**
483
     * List resources Wrapper (supports paging info) using Smartsheet REST API.
484
     *
485
     * @throws IllegalArgumentException    : if any argument is null, or path is empty string
486
     * @throws InvalidRequestException     : if there is any problem with the REST API request
487
     * @throws AuthorizationException      : if there is any problem with the REST API authorization(access token)
488
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
489
     * @throws SmartsheetRestException     : if there is any other REST API related error occurred during the operation
490
     * @throws SmartsheetException         : if there is any other error occurred during the operation
491
     */
492
    protected <T> PagedResult<T> listResourcesWithWrapper(String path, Class<T> objectClass) throws SmartsheetException {
493
        Util.throwIfNull(path, objectClass);
1✔
494
        Util.throwIfEmpty(path);
1✔
495

496
        HttpRequest request;
497
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
1✔
498

499
        PagedResult<T> obj = null;
1✔
500
        try {
501
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
502
            switch (response.getStatusCode()) {
1✔
503
                case 200:
504
                    obj = this.smartsheet.getJsonSerializer().deserializeDataWrapper(objectClass,
1✔
505
                            response.getEntity().getContent());
1✔
506
                    break;
1✔
507
                default:
508
                    handleError(response);
×
509
            }
510
        } finally {
511
            smartsheet.getHttpClient().releaseConnection();
1✔
512
        }
513

514
        return obj;
1✔
515
    }
516

517
    /**
518
     * List resources with token-based pagination using a custom deserializer.
519
     * This generic method allows for flexible deserialization of paginated results.
520
     *
521
     * @param <T> the generic type of the data items
522
     * @param path the relative path of the resource collections
523
     * @param deserializer the custom deserializer for the data items
524
     * @return the token paginated result
525
     * @throws IllegalArgumentException : if any argument is null, or path is empty string
526
     * @throws InvalidRequestException : if there is any problem with the REST API request
527
     * @throws AuthorizationException : if there is any problem with the REST API authorization(access token)
528
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
529
     * @throws SmartsheetRestException : if there is any other REST API related error occurred during the operation
530
     * @throws SmartsheetException : if there is any other error occurred during the operation
531
     */
532
    protected <T> TokenPaginatedResult<T> listResourcesWithTokenPagination(String path, JsonDeserializer<List<T>> deserializer)
533
            throws SmartsheetException {
534
        return listResourcesWithTokenPagination(path, null, deserializer);
×
535
    }
536

537
    /**
538
     * List resources with token-based pagination based on data type class type reference
539
     *
540
     * @param <T> the generic type of the data items
541
     * @param path the relative path of the resource collections
542
     * @param objectClass actual data type wrapped in TokenPaginatedResult
543
     * @return the token paginated result
544
     * @throws IllegalArgumentException : if any argument is null, or path is empty string
545
     * @throws InvalidRequestException : if there is any problem with the REST API request
546
     * @throws AuthorizationException : if there is any problem with the REST API authorization(access token)
547
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
548
     * @throws SmartsheetRestException : if there is any other REST API related error occurred during the operation
549
     * @throws SmartsheetException : if there is any other error occurred during the operation
550
     */
551
    protected <T> TokenPaginatedResult<T> listResourcesWithTokenPagination(String path, Class<T> objectClass)
552
            throws SmartsheetException {
553
        return listResourcesWithTokenPagination(path, objectClass, null);
1✔
554
    }
555

556
    private <T> TokenPaginatedResult<T> listResourcesWithTokenPagination(String path, Class<T> objectClass,
557
                                                                         JsonDeserializer<List<T>> deserializer)
558
            throws SmartsheetException {
559
        Util.throwIfNull(path);
1✔
560
        Util.throwIfEmpty(path);
1✔
561
        Util.throwIfBothNotNullOrNull(objectClass, deserializer);
1✔
562

563
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
1✔
564

565
        TokenPaginatedResult<T> obj = null;
1✔
566
        try {
567
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
568
            if (response.getStatusCode() == 200) {
1✔
569
                if (deserializer != null) {
1✔
570
                    obj = this.smartsheet.getJsonSerializer()
×
571
                            .deserializeTokenPaginatedResult(deserializer, response.getEntity().getContent());
×
572
                } else {
573
                    obj = this.smartsheet.getJsonSerializer()
1✔
574
                            .deserializeTokenPaginatedResult(objectClass, response.getEntity().getContent());
1✔
575
                }
576
            } else {
577
                handleError(response);
×
578
            }
579
        } finally {
580
            smartsheet.getHttpClient().releaseConnection();
1✔
581
        }
582

583
        return obj;
1✔
584
    }
585

586
    /**
587
     * List resources with token-based pagination based on data type class type reference
588
     *
589
     * @param <T> the generic type of the data items
590
     * @param path the relative path of the resource collections
591
     * @param objectClass actual data type wrapped in ListAssetSharesResponse
592
     * @return the token paginated result
593
     * @throws IllegalArgumentException : if any argument is null, or path is empty string
594
     * @throws InvalidRequestException : if there is any problem with the REST API request
595
     * @throws AuthorizationException : if there is any problem with the REST API authorization(access token)
596
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
597
     * @throws SmartsheetRestException : if there is any other REST API related error occurred during the operation
598
     * @throws SmartsheetException : if there is any other error occurred during the operation
599
     */
600
    protected <T> ListAssetSharesResponse<T> listAssetSharesWithTokenPagination(String path, Class<T> objectClass)
601
            throws SmartsheetException {
602
        Util.throwIfNull(path, objectClass);
1✔
603
        Util.throwIfEmpty(path);
1✔
604

605
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
1✔
606

607
        ListAssetSharesResponse<T> obj = null;
1✔
608
        try {
609
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
610
            if (response.getStatusCode() == 200) {
1✔
611
                obj = this.smartsheet.getJsonSerializer()
1✔
612
                        .listAssetSharesTokenPaginatedResult(objectClass, response.getEntity().getContent());
1✔
613
            } else {
614
                handleError(response);
×
615
            }
616
        } finally {
617
            smartsheet.getHttpClient().releaseConnection();
1✔
618
        }
619

620
        return obj;
1✔
621
    }
622

623
    /**
624
     * Delete a resource from Smartsheet REST API.
625
     * <p>
626
     * Exceptions:
627
     * IllegalArgumentException : if any argument is null, or path is empty string
628
     * InvalidRequestException : if there is any problem with the REST API request
629
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
630
     * ResourceNotFoundException : if the resource can not be found
631
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
632
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
633
     * SmartsheetException : if there is any other error occurred during the operation
634
     *
635
     * @param <T>         the generic type
636
     * @param path        the relative path of the resource
637
     * @param objectClass the resource object class
638
     * @throws SmartsheetException the smartsheet exception
639
     */
640
    protected <T> void deleteResource(String path, Class<T> objectClass) throws SmartsheetException {
641
        Util.throwIfNull(path, objectClass);
1✔
642
        Util.throwIfEmpty(path);
1✔
643

644
        HttpRequest request;
645
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.DELETE);
1✔
646

647
        try {
648
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
649
            switch (response.getStatusCode()) {
1✔
650
                case 200:
651
                    this.smartsheet.getJsonSerializer().deserializeResult(objectClass,
1✔
652
                            response.getEntity().getContent());
1✔
653
                    break;
1✔
654
                default:
655
                    handleError(response);
×
656
            }
657
        } finally {
658
            smartsheet.getHttpClient().releaseConnection();
1✔
659
        }
660
    }
1✔
661
    /**
662
     * Delete resources and return a list from Smartsheet REST API.
663
     * <p>
664
     * Exceptions:
665
     * IllegalArgumentException : if any argument is null, or path is empty string
666
     * InvalidRequestException : if there is any problem with the REST API request
667
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
668
     * ResourceNotFoundException : if the resource can not be found
669
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
670
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
671
     * SmartsheetException : if there is any other error occurred during the operation
672
     *
673
     * @param <T>         the generic type
674
     * @param path        the relative path of the resource
675
     * @param objectClass the resource object class
676
     * @return List of ids deleted
677
     * @throws SmartsheetException the smartsheet exception
678
     */
679

680
    protected <T> List<T> deleteListResources(String path, Class<T> objectClass) throws SmartsheetException {
681
        Util.throwIfNull(path, objectClass);
1✔
682
        Util.throwIfEmpty(path);
1✔
683

684
        Result<List<T>> obj = null;
1✔
685
        HttpRequest request;
686
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.DELETE);
1✔
687
        try {
688
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
689
            switch (response.getStatusCode()) {
1✔
690
                case 200:
691
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(objectClass,
1✔
692
                            response.getEntity().getContent());
1✔
693
                    break;
1✔
694
                default:
695
                    handleError(response);
×
696
            }
697
        } finally {
698
            smartsheet.getHttpClient().releaseConnection();
1✔
699
        }
700
        return obj.getResult();
1✔
701
    }
702

703
    /**
704
     * Post an object to Smartsheet REST API and receive a list of objects from response.
705
     * <p>
706
     * Parameters: - path : the relative path of the resource collections - objectToPost : the object to post -
707
     * objectClassToReceive : the resource object class to receive
708
     * <p>
709
     * Returns: the object list
710
     * <p>
711
     * Exceptions:
712
     * IllegalArgumentException : if any argument is null, or path is empty string
713
     * InvalidRequestException : if there is any problem with the REST API request
714
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
715
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
716
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
717
     * SmartsheetException : if there is any other error occurred during the operation
718
     *
719
     * @param <T>                  the generic type
720
     * @param <S>                  the generic type
721
     * @param path                 the path
722
     * @param objectToPost         the object to post
723
     * @param objectClassToReceive the object class to receive
724
     * @return the list
725
     * @throws SmartsheetException the smartsheet exception
726
     */
727
    protected <T, S> List<S> postAndReceiveList(String path, T objectToPost, Class<S> objectClassToReceive) throws SmartsheetException {
728
        Util.throwIfNull(path, objectToPost, objectClassToReceive);
1✔
729
        Util.throwIfEmpty(path);
1✔
730

731
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.POST);
1✔
732

733
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
734
        this.smartsheet.getJsonSerializer().serialize(objectToPost, objectBytesStream);
1✔
735
        HttpEntity entity = new HttpEntity();
1✔
736
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
737
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
738
        entity.setContentLength(objectBytesStream.size());
1✔
739
        request.setEntity(entity);
1✔
740

741
        List<S> obj = null;
1✔
742
        try {
743
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
744
            switch (response.getStatusCode()) {
1✔
745
                case 200:
746
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(objectClassToReceive,
1✔
747
                            response.getEntity().getContent()).getResult();
1✔
748
                    break;
1✔
749
                default:
750
                    handleError(response);
×
751
            }
752
        } finally {
753
            smartsheet.getHttpClient().releaseConnection();
1✔
754
        }
755

756
        return obj;
1✔
757
    }
758

759
    /**
760
     * Partially update a resource using Smartsheet REST API with PATCH method.
761
     * <p>
762
     * Exceptions:
763
     * IllegalArgumentException : if any argument is null, or path is empty string
764
     * InvalidRequestException : if there is any problem with the REST API request
765
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
766
     * ResourceNotFoundException : if the resource can not be found
767
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
768
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
769
     * SmartsheetException : if there is any other error occurred during the operation
770
     *
771
     * @param <T>         the generic type
772
     * @param path        the relative path of the resource
773
     * @param objectClass the resource object class
774
     * @param object      the object to patch
775
     * @return the updated resource
776
     * @throws SmartsheetException the smartsheet exception
777
     */
778
    protected <T> T patchResource(String path, Class<T> objectClass, Object object) throws SmartsheetException {
779
        Util.throwIfNull(path, object);
1✔
780
        Util.throwIfEmpty(path);
1✔
781

782
        HttpRequest request;
783
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.PATCH);
1✔
784

785
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
786
        this.smartsheet.getJsonSerializer().serialize(object, objectBytesStream);
1✔
787
        HttpEntity entity = new HttpEntity();
1✔
788
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
789
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
790
        entity.setContentLength(objectBytesStream.size());
1✔
791
        request.setEntity(entity);
1✔
792

793
        T obj = null;
1✔
794
        try {
795
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
796
            if (response.getStatusCode() == 200) {
1✔
797
                obj = this.smartsheet.getJsonSerializer().deserialize(objectClass,
1✔
798
                        response.getEntity().getContent());
1✔
799
            } else {
800
                handleError(response);
×
801
            }
802
        } catch (IOException e) {
×
803
            throw new RuntimeException(e);
×
804
        } finally {
805
            smartsheet.getHttpClient().releaseConnection();
1✔
806
        }
807

808
        return obj;
1✔
809
    }
810

811
    /**
812
     * Post an object to Smartsheet REST API and receive a CopyOrMoveRowResult object from response.
813
     * <p>
814
     * Parameters: - path : the relative path of the resource collections - objectToPost : the object to post -
815
     * <p>
816
     * Returns: the object
817
     * <p>
818
     * Exceptions:
819
     * IllegalArgumentException : if any argument is null, or path is empty string
820
     * InvalidRequestException : if there is any problem with the REST API request
821
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
822
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
823
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
824
     * SmartsheetException : if there is any other error occurred during the operation
825
     *
826
     * @param path         the path
827
     * @param objectToPost the object to post
828
     * @return the result object
829
     * @throws SmartsheetException the smartsheet exception
830
     */
831
    protected CopyOrMoveRowResult postAndReceiveRowObject(String path, CopyOrMoveRowDirective objectToPost) throws SmartsheetException {
832
        Util.throwIfNull(path, objectToPost);
1✔
833
        Util.throwIfEmpty(path);
1✔
834

835
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.POST);
1✔
836

837
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
838
        this.smartsheet.getJsonSerializer().serialize(objectToPost, objectBytesStream);
1✔
839
        HttpEntity entity = new HttpEntity();
1✔
840
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
841
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
842
        entity.setContentLength(objectBytesStream.size());
1✔
843
        request.setEntity(entity);
1✔
844

845
        CopyOrMoveRowResult obj = null;
1✔
846
        try {
847
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
848
            switch (response.getStatusCode()) {
1✔
849
                case 200:
850
                    obj = this.smartsheet.getJsonSerializer().deserializeCopyOrMoveRow(
1✔
851
                            response.getEntity().getContent());
1✔
852
                    break;
1✔
853
                default:
854
                    handleError(response);
×
855
            }
856
        } finally {
857
            smartsheet.getHttpClient().releaseConnection();
1✔
858
        }
859

860
        return obj;
1✔
861
    }
862

863
    /**
864
     * Put an object to Smartsheet REST API and receive a list of objects from response.
865
     *
866
     * @param <T>                  the generic type
867
     * @param <S>                  the generic type
868
     * @param path                 the relative path of the resource collections
869
     * @param objectToPut          the object to put
870
     * @param objectClassToReceive the resource object class to receive
871
     * @return the object list
872
     * @throws IllegalArgumentException    : if any argument is null, or path is empty string
873
     * @throws InvalidRequestException     : if there is any problem with the REST API request
874
     * @throws AuthorizationException      : if there is any problem with the REST API authorization(access token)
875
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
876
     * @throws SmartsheetRestException     : if there is any other REST API related error occurred during the operation
877
     * @throws SmartsheetException         : if there is any other error occurred during the operation
878
     */
879
    protected <T, S> List<S> putAndReceiveList(String path, T objectToPut, Class<S> objectClassToReceive)
880
            throws SmartsheetException {
881
        Util.throwIfNull(path, objectToPut, objectClassToReceive);
1✔
882
        Util.throwIfEmpty(path);
1✔
883

884
        HttpRequest request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.PUT);
1✔
885

886
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
887
        this.smartsheet.getJsonSerializer().serialize(objectToPut, objectBytesStream);
1✔
888
        HttpEntity entity = new HttpEntity();
1✔
889
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
890
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
891
        entity.setContentLength(objectBytesStream.size());
1✔
892
        request.setEntity(entity);
1✔
893

894
        List<S> obj = null;
1✔
895
        try {
896
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
897
            switch (response.getStatusCode()) {
1✔
898
                case 200:
899
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(
1✔
900
                            objectClassToReceive, response.getEntity().getContent()).getResult();
1✔
901
                    break;
1✔
902
                default:
903
                    handleError(response);
×
904
            }
905
        } finally {
906
            smartsheet.getHttpClient().releaseConnection();
1✔
907
        }
908

909
        return obj;
1✔
910
    }
911

912
    /**
913
     * Create an HttpRequest.
914
     *
915
     * @param uri    the URI
916
     * @param method the HttpMethod
917
     * @return the http request
918
     */
919
    protected HttpRequest createHttpRequest(URI uri, HttpMethod method) {
920
        HttpRequest request = new HttpRequest();
1✔
921
        request.setUri(uri);
1✔
922
        request.setMethod(method);
1✔
923

924
        // Set authorization header
925
        request.setHeaders(createHeaders());
1✔
926

927
        return request;
1✔
928
    }
929

930
    protected HttpPost createHttpPost(URI uri) {
931
        HttpPost httpPost = new HttpPost(uri);
1✔
932
        Map<String, String> headers = createHeaders();
1✔
933
        for (Map.Entry<String, String> entry : headers.entrySet()) {
1✔
934
            httpPost.addHeader(entry.getKey(), entry.getValue());
1✔
935
        }
1✔
936
        return httpPost;
1✔
937
    }
938

939
    /**
940
     * Attach a file
941
     */
942
    public Attachment attachFile(String url, InputStream inputStream, String contentType, long contentLength, String attachmentName)
943
            throws SmartsheetException {
944
        Util.throwIfNull(inputStream, contentType);
1✔
945
        HttpRequest request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(url), HttpMethod.POST);
1✔
946
        request.getHeaders().put(
1✔
947
                "Content-Disposition",
948
                "attachment; filename=\"" + URLEncoder.encode(attachmentName, StandardCharsets.UTF_8) + "\""
1✔
949
        );
950
        HttpEntity entity = new HttpEntity();
1✔
951
        entity.setContentType(contentType);
1✔
952
        entity.setContent(new LengthEnforcingInputStream(inputStream, contentLength));
1✔
953
        entity.setContentLength(contentLength);
1✔
954
        request.setEntity(entity);
1✔
955

956
        Attachment attachment = null;
1✔
957
        try {
958
            HttpResponse response = this.getSmartsheet().getHttpClient().request(request);
1✔
959
            switch (response.getStatusCode()) {
1✔
960
                case 200:
961
                    attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
1✔
962
                            response.getEntity().getContent()).getResult();
1✔
963
                    break;
1✔
964
                default:
965
                    handleError(response);
×
966
            }
967
        } finally {
968
            this.getSmartsheet().getHttpClient().releaseConnection();
1✔
969
        }
970

971
        return attachment;
1✔
972
    }
973

974
    /**
975
     * Create a multipart upload request.
976
     *
977
     * @param url         the url
978
     * @param t           the object to create
979
     * @param partName    the name of the part
980
     * @param inputstream the file inputstream
981
     * @param contentType the type of the file to be attached
982
     * @return the http request
983
     * @throws SmartsheetException may be thrown in the method
984
     */
985
    public <T> Attachment attachFile(String url, T t, String partName, InputStream inputstream, String contentType, String attachmentName)
986
            throws SmartsheetException {
987
        Util.throwIfNull(inputstream, contentType);
×
988
        Attachment attachment = null;
×
989
        final String boundary = "----" + System.currentTimeMillis();
×
990

991
        CloseableHttpClient httpClient = HttpClients.createDefault();
×
992
        HttpPost uploadFile = createHttpPost(this.getSmartsheet().getBaseURI().resolve(url));
×
993

994
        try {
995
            uploadFile.setHeader(HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
×
996
        } catch (Exception e) {
×
997
            throw new RuntimeException(e);
×
998
        }
×
999

1000
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
×
1001
        builder.setBoundary(boundary);
×
1002
        builder.addTextBody(partName, this.getSmartsheet().getJsonSerializer().serialize(t), ContentType.APPLICATION_JSON);
×
1003
        builder.addBinaryBody("file", inputstream, ContentType.create(contentType), attachmentName);
×
1004
        org.apache.http.HttpEntity multipart = builder.build();
×
1005

1006
        uploadFile.setEntity(multipart);
×
1007

1008
        try {
1009
            CloseableHttpResponse response = httpClient.execute(uploadFile);
×
1010
            org.apache.http.HttpEntity responseEntity = response.getEntity();
×
1011
            attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
×
1012
                    responseEntity.getContent()).getResult();
×
1013
        } catch (Exception e) {
×
1014
            throw new RuntimeException(e);
×
1015
        }
×
1016
        return attachment;
×
1017
    }
1018

1019
    /**
1020
     * Handles an error HttpResponse (non-200) returned by Smartsheet REST API.
1021
     *
1022
     * @param response the HttpResponse
1023
     * @throws SmartsheetException     the smartsheet exception
1024
     * @throws SmartsheetRestException : the exception corresponding to the error
1025
     */
1026
    protected void handleError(HttpResponse response) throws SmartsheetException {
1027

1028
        com.smartsheet.api.models.Error error;
1029
        try {
1030
            error = this.smartsheet.getJsonSerializer().deserialize(
1✔
1031
                    com.smartsheet.api.models.Error.class, response.getEntity().getContent());
1✔
1032
        } catch (IOException e) {
×
1033
            throw new SmartsheetException(e);
×
1034
        }
1✔
1035

1036
        ErrorCode code = ErrorCode.getErrorCode(response.getStatusCode());
1✔
1037

1038
        if (code == null) {
1✔
1039
            throw new SmartsheetRestException(error);
×
1040
        }
1041

1042
        try {
1043
            throw code.getException(error);
1✔
1044
        } catch (IllegalArgumentException e) {
×
1045
            throw new SmartsheetException(e);
×
1046
        } catch (SecurityException e) {
×
1047
            throw new SmartsheetException(e);
×
1048
        }
1049
    }
1050

1051
    /**
1052
     * Gets the smartsheet.
1053
     *
1054
     * @return the smartsheet
1055
     */
1056
    public SmartsheetImpl getSmartsheet() {
1057
        return smartsheet;
1✔
1058
    }
1059

1060
    /**
1061
     * Get a sheet as a file.
1062
     *
1063
     * @param path         the path
1064
     * @param fileType     the output file type
1065
     * @param outputStream the OutputStream to which the file will be written
1066
     * @throws InvalidRequestException     : if there is any problem with the REST API request
1067
     * @throws AuthorizationException      : if there is any problem with the REST API authorization(access token)
1068
     * @throws ResourceNotFoundException   : if the resource can not be found
1069
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
1070
     * @throws SmartsheetRestException     : if there is any other REST API related error occurred during the operation
1071
     * @throws SmartsheetException         : if there is any other error occurred during the operation
1072
     */
1073
    public void getResourceAsFile(String path, String fileType, OutputStream outputStream)
1074
            throws SmartsheetException {
1075
        Util.throwIfNull(outputStream, fileType);
1✔
1076

1077
        HttpRequest request;
1078
        request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(path), HttpMethod.GET);
1✔
1079
        request.getHeaders().put("Accept", fileType);
1✔
1080

1081
        try {
1082
            HttpResponse response = getSmartsheet().getHttpClient().request(request);
1✔
1083

1084
            switch (response.getStatusCode()) {
1✔
1085
                case 200:
1086
                    try {
1087
                        copyStream(response.getEntity().getContent(), outputStream);
1✔
1088
                    } catch (IOException e) {
×
1089
                        throw new SmartsheetException(e);
×
1090
                    }
1✔
1091
                    break;
1092
                default:
1093
                    handleError(response);
×
1094
            }
1095
        } finally {
1096
            getSmartsheet().getHttpClient().releaseConnection();
1✔
1097
        }
1098
    }
1✔
1099

1100
    /*
1101
     * Copy an input stream to an output stream.
1102
     *
1103
     * @param input The input stream to copy.
1104
     *
1105
     * @param output the output stream to write to.
1106
     *
1107
     * @throws IOException if there is trouble reading or writing to the streams.
1108
     */
1109

1110
    /**
1111
     * Copy stream.
1112
     *
1113
     * @param input  the input
1114
     * @param output the output
1115
     * @throws IOException Signals that an I/O exception has occurred.
1116
     * @deprecated replace with StreamUtil.copyContentIntoOutputStream()
1117
     */
1118
    @Deprecated(since = "2.0.0", forRemoval = true)
1119
    private static void copyStream(InputStream input, OutputStream output) throws IOException {
1120
        byte[] buffer = new byte[BUFFER_SIZE];
1✔
1121
        int len;
1122
        while ((len = input.read(buffer)) != -1) {
1✔
1123
            output.write(buffer, 0, len);
1✔
1124
        }
1125
    }
1✔
1126

1127
    /**
1128
     * @return a map of headers to be used when making requests.
1129
     */
1130
    Map<String, String> createHeaders() {
1131
        Map<String, String> headers = new HashMap<>();
1✔
1132
        headers.put("Authorization", "Bearer " + smartsheet.getAccessToken());
1✔
1133
        headers.put(HEADER_CONTENT_TYPE, JSON_CONTENT_TYPE);
1✔
1134

1135
        // Set assumed user
1136
        if (smartsheet.getAssumedUser() != null) {
1✔
1137
            headers.put("Assume-User", URLEncoder.encode(smartsheet.getAssumedUser(), StandardCharsets.UTF_8));
×
1138
        }
1139
        if (smartsheet.getChangeAgent() != null) {
1✔
1140
            headers.put("Smartsheet-Change-Agent", URLEncoder.encode(smartsheet.getChangeAgent(), StandardCharsets.UTF_8));
1✔
1141
        }
1142
        if (smartsheet.getUserAgent() != null) {
1✔
1143
            headers.put("User-Agent", smartsheet.getUserAgent());
1✔
1144
        }
1145
        return headers;
1✔
1146
    }
1147

1148
    int getResponseLogLength() {
1149
        // not cached to allow for it to be changed dynamically by client code
1150
        return Integer.getInteger(PROPERTY_RESPONSE_LOG_CHARS, 1024);
×
1151
    }
1152
}
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