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

smartsheet / smartsheet-java-sdk / #67

09 Jul 2026 02:57PM UTC coverage: 59.797% (-0.2%) from 59.997%
#67

push

github

web-flow
Merge pull request #183 from smartsheet/release/4.2.0

Prepare for release v4.2.0

4532 of 7579 relevant lines covered (59.8%)

0.6 hits per line

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

67.9
/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 response resource type
401
     * @param <S>         the request body type
402
     * @param path        the relative path of the resource
403
     * @param objectClass the resource object class
404
     * @param object      the object to create
405
     * @return the updated resource
406
     * @throws SmartsheetException the smartsheet exception
407
     */
408
    protected <T, S> T updateResource(String path, Class<T> objectClass, S object) throws SmartsheetException {
409
        Util.throwIfNull(path, object);
1✔
410
        Util.throwIfEmpty(path);
1✔
411

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

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

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

438
        return obj;
1✔
439
    }
440

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

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

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

480
        return obj;
×
481
    }
482

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

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

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

515
        return obj;
1✔
516
    }
517

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

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

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

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

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

584
        return obj;
1✔
585
    }
586

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

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

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

621
        return obj;
1✔
622
    }
623

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

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

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

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

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

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

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

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

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

757
        return obj;
1✔
758
    }
759

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

783
        HttpRequest request;
784
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.PUT);
×
785

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

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

809
        return obj;
×
810
    }
811

812
    /**
813
     * Partially update a resource using Smartsheet REST API with PATCH method.
814
     * <p>
815
     * Exceptions:
816
     * IllegalArgumentException : if any argument is null, or path is empty string
817
     * InvalidRequestException : if there is any problem with the REST API request
818
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
819
     * ResourceNotFoundException : if the resource can not be found
820
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
821
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
822
     * SmartsheetException : if there is any other error occurred during the operation
823
     *
824
     * @param <T>         the generic type
825
     * @param path        the relative path of the resource
826
     * @param objectClass the resource object class
827
     * @param object      the object to patch
828
     * @return the updated resource
829
     * @throws SmartsheetException the smartsheet exception
830
     */
831
    protected <T> T patchResource(String path, Class<T> objectClass, Object object) throws SmartsheetException {
832
        Util.throwIfNull(path, object);
1✔
833
        Util.throwIfEmpty(path);
1✔
834

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

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

846
        T obj = null;
1✔
847
        try {
848
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
849
            if (response.getStatusCode() == 200) {
1✔
850
                obj = this.smartsheet.getJsonSerializer().deserialize(objectClass,
1✔
851
                        response.getEntity().getContent());
1✔
852
            } else {
853
                handleError(response);
×
854
            }
855
        } catch (IOException e) {
×
856
            throw new RuntimeException(e);
×
857
        } finally {
858
            smartsheet.getHttpClient().releaseConnection();
1✔
859
        }
860

861
        return obj;
1✔
862
    }
863

864
    /**
865
     * Post an object to Smartsheet REST API and receive a CopyOrMoveRowResult object from response.
866
     * <p>
867
     * Parameters: - path : the relative path of the resource collections - objectToPost : the object to post -
868
     * <p>
869
     * Returns: the object
870
     * <p>
871
     * Exceptions:
872
     * IllegalArgumentException : if any argument is null, or path is empty string
873
     * InvalidRequestException : if there is any problem with the REST API request
874
     * AuthorizationException : if there is any problem with the REST API authorization(access token)
875
     * ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
876
     * SmartsheetRestException : if there is any other REST API related error occurred during the operation
877
     * SmartsheetException : if there is any other error occurred during the operation
878
     *
879
     * @param path         the path
880
     * @param objectToPost the object to post
881
     * @return the result object
882
     * @throws SmartsheetException the smartsheet exception
883
     */
884
    protected CopyOrMoveRowResult postAndReceiveRowObject(String path, CopyOrMoveRowDirective objectToPost) throws SmartsheetException {
885
        Util.throwIfNull(path, objectToPost);
1✔
886
        Util.throwIfEmpty(path);
1✔
887

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

890
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
891
        this.smartsheet.getJsonSerializer().serialize(objectToPost, objectBytesStream);
1✔
892
        HttpEntity entity = new HttpEntity();
1✔
893
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
894
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
895
        entity.setContentLength(objectBytesStream.size());
1✔
896
        request.setEntity(entity);
1✔
897

898
        CopyOrMoveRowResult obj = null;
1✔
899
        try {
900
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
901
            switch (response.getStatusCode()) {
1✔
902
                case 200:
903
                    obj = this.smartsheet.getJsonSerializer().deserializeCopyOrMoveRow(
1✔
904
                            response.getEntity().getContent());
1✔
905
                    break;
1✔
906
                default:
907
                    handleError(response);
×
908
            }
909
        } finally {
910
            smartsheet.getHttpClient().releaseConnection();
1✔
911
        }
912

913
        return obj;
1✔
914
    }
915

916
    /**
917
     * Put an object to Smartsheet REST API and receive a list of objects from response.
918
     *
919
     * @param <T>                  the generic type
920
     * @param <S>                  the generic type
921
     * @param path                 the relative path of the resource collections
922
     * @param objectToPut          the object to put
923
     * @param objectClassToReceive the resource object class to receive
924
     * @return the object list
925
     * @throws IllegalArgumentException    : if any argument is null, or path is empty string
926
     * @throws InvalidRequestException     : if there is any problem with the REST API request
927
     * @throws AuthorizationException      : if there is any problem with the REST API authorization(access token)
928
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
929
     * @throws SmartsheetRestException     : if there is any other REST API related error occurred during the operation
930
     * @throws SmartsheetException         : if there is any other error occurred during the operation
931
     */
932
    protected <T, S> List<S> putAndReceiveList(String path, T objectToPut, Class<S> objectClassToReceive)
933
            throws SmartsheetException {
934
        Util.throwIfNull(path, objectToPut, objectClassToReceive);
1✔
935
        Util.throwIfEmpty(path);
1✔
936

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

939
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
940
        this.smartsheet.getJsonSerializer().serialize(objectToPut, objectBytesStream);
1✔
941
        HttpEntity entity = new HttpEntity();
1✔
942
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
943
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
944
        entity.setContentLength(objectBytesStream.size());
1✔
945
        request.setEntity(entity);
1✔
946

947
        List<S> obj = null;
1✔
948
        try {
949
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
950
            switch (response.getStatusCode()) {
1✔
951
                case 200:
952
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(
1✔
953
                            objectClassToReceive, response.getEntity().getContent()).getResult();
1✔
954
                    break;
1✔
955
                default:
956
                    handleError(response);
×
957
            }
958
        } finally {
959
            smartsheet.getHttpClient().releaseConnection();
1✔
960
        }
961

962
        return obj;
1✔
963
    }
964

965
    /**
966
     * Create an HttpRequest.
967
     *
968
     * @param uri    the URI
969
     * @param method the HttpMethod
970
     * @return the http request
971
     */
972
    protected HttpRequest createHttpRequest(URI uri, HttpMethod method) {
973
        HttpRequest request = new HttpRequest();
1✔
974
        request.setUri(uri);
1✔
975
        request.setMethod(method);
1✔
976

977
        // Set authorization header
978
        request.setHeaders(createHeaders());
1✔
979

980
        return request;
1✔
981
    }
982

983
    protected HttpPost createHttpPost(URI uri) {
984
        HttpPost httpPost = new HttpPost(uri);
1✔
985
        Map<String, String> headers = createHeaders();
1✔
986
        for (Map.Entry<String, String> entry : headers.entrySet()) {
1✔
987
            httpPost.addHeader(entry.getKey(), entry.getValue());
1✔
988
        }
1✔
989
        return httpPost;
1✔
990
    }
991

992
    /**
993
     * Attach a file
994
     */
995
    public Attachment attachFile(String url, InputStream inputStream, String contentType, long contentLength, String attachmentName)
996
            throws SmartsheetException {
997
        Util.throwIfNull(inputStream, contentType);
1✔
998
        HttpRequest request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(url), HttpMethod.POST);
1✔
999
        request.getHeaders().put(
1✔
1000
                "Content-Disposition",
1001
                "attachment; filename=\"" + URLEncoder.encode(attachmentName, StandardCharsets.UTF_8) + "\""
1✔
1002
        );
1003
        HttpEntity entity = new HttpEntity();
1✔
1004
        entity.setContentType(contentType);
1✔
1005
        entity.setContent(new LengthEnforcingInputStream(inputStream, contentLength));
1✔
1006
        entity.setContentLength(contentLength);
1✔
1007
        request.setEntity(entity);
1✔
1008

1009
        Attachment attachment = null;
1✔
1010
        try {
1011
            HttpResponse response = this.getSmartsheet().getHttpClient().request(request);
1✔
1012
            switch (response.getStatusCode()) {
1✔
1013
                case 200:
1014
                    attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
1✔
1015
                            response.getEntity().getContent()).getResult();
1✔
1016
                    break;
1✔
1017
                default:
1018
                    handleError(response);
×
1019
            }
1020
        } finally {
1021
            this.getSmartsheet().getHttpClient().releaseConnection();
1✔
1022
        }
1023

1024
        return attachment;
1✔
1025
    }
1026

1027
    /**
1028
     * Create a multipart upload request.
1029
     *
1030
     * @param url         the url
1031
     * @param t           the object to create
1032
     * @param partName    the name of the part
1033
     * @param inputstream the file inputstream
1034
     * @param contentType the type of the file to be attached
1035
     * @return the http request
1036
     * @throws SmartsheetException may be thrown in the method
1037
     */
1038
    public <T> Attachment attachFile(String url, T t, String partName, InputStream inputstream, String contentType, String attachmentName)
1039
            throws SmartsheetException {
1040
        Util.throwIfNull(inputstream, contentType);
×
1041
        Attachment attachment = null;
×
1042
        final String boundary = "----" + System.currentTimeMillis();
×
1043

1044
        CloseableHttpClient httpClient = HttpClients.createDefault();
×
1045
        HttpPost uploadFile = createHttpPost(this.getSmartsheet().getBaseURI().resolve(url));
×
1046

1047
        try {
1048
            uploadFile.setHeader(HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
×
1049
        } catch (Exception e) {
×
1050
            throw new RuntimeException(e);
×
1051
        }
×
1052

1053
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
×
1054
        builder.setBoundary(boundary);
×
1055
        builder.addTextBody(partName, this.getSmartsheet().getJsonSerializer().serialize(t), ContentType.APPLICATION_JSON);
×
1056
        builder.addBinaryBody("file", inputstream, ContentType.create(contentType), attachmentName);
×
1057
        org.apache.http.HttpEntity multipart = builder.build();
×
1058

1059
        uploadFile.setEntity(multipart);
×
1060

1061
        try {
1062
            CloseableHttpResponse response = httpClient.execute(uploadFile);
×
1063
            org.apache.http.HttpEntity responseEntity = response.getEntity();
×
1064
            attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
×
1065
                    responseEntity.getContent()).getResult();
×
1066
        } catch (Exception e) {
×
1067
            throw new RuntimeException(e);
×
1068
        }
×
1069
        return attachment;
×
1070
    }
1071

1072
    /**
1073
     * Handles an error HttpResponse (non-200) returned by Smartsheet REST API.
1074
     *
1075
     * @param response the HttpResponse
1076
     * @throws SmartsheetException     the smartsheet exception
1077
     * @throws SmartsheetRestException : the exception corresponding to the error
1078
     */
1079
    protected void handleError(HttpResponse response) throws SmartsheetException {
1080

1081
        com.smartsheet.api.models.Error error;
1082
        try {
1083
            error = this.smartsheet.getJsonSerializer().deserialize(
1✔
1084
                    com.smartsheet.api.models.Error.class, response.getEntity().getContent());
1✔
1085
        } catch (IOException e) {
×
1086
            throw new SmartsheetException(e);
×
1087
        }
1✔
1088

1089
        ErrorCode code = ErrorCode.getErrorCode(response.getStatusCode());
1✔
1090

1091
        if (code == null) {
1✔
1092
            throw new SmartsheetRestException(error);
×
1093
        }
1094

1095
        try {
1096
            throw code.getException(error);
1✔
1097
        } catch (IllegalArgumentException e) {
×
1098
            throw new SmartsheetException(e);
×
1099
        } catch (SecurityException e) {
×
1100
            throw new SmartsheetException(e);
×
1101
        }
1102
    }
1103

1104
    /**
1105
     * Gets the smartsheet.
1106
     *
1107
     * @return the smartsheet
1108
     */
1109
    public SmartsheetImpl getSmartsheet() {
1110
        return smartsheet;
1✔
1111
    }
1112

1113
    /**
1114
     * Get a sheet as a file.
1115
     *
1116
     * @param path         the path
1117
     * @param fileType     the output file type
1118
     * @param outputStream the OutputStream to which the file will be written
1119
     * @throws InvalidRequestException     : if there is any problem with the REST API request
1120
     * @throws AuthorizationException      : if there is any problem with the REST API authorization(access token)
1121
     * @throws ResourceNotFoundException   : if the resource can not be found
1122
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
1123
     * @throws SmartsheetRestException     : if there is any other REST API related error occurred during the operation
1124
     * @throws SmartsheetException         : if there is any other error occurred during the operation
1125
     */
1126
    public void getResourceAsFile(String path, String fileType, OutputStream outputStream)
1127
            throws SmartsheetException {
1128
        Util.throwIfNull(outputStream, fileType);
1✔
1129

1130
        HttpRequest request;
1131
        request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(path), HttpMethod.GET);
1✔
1132
        request.getHeaders().put("Accept", fileType);
1✔
1133

1134
        try {
1135
            HttpResponse response = getSmartsheet().getHttpClient().request(request);
1✔
1136

1137
            switch (response.getStatusCode()) {
1✔
1138
                case 200:
1139
                    try {
1140
                        copyStream(response.getEntity().getContent(), outputStream);
1✔
1141
                    } catch (IOException e) {
×
1142
                        throw new SmartsheetException(e);
×
1143
                    }
1✔
1144
                    break;
1145
                default:
1146
                    handleError(response);
×
1147
            }
1148
        } finally {
1149
            getSmartsheet().getHttpClient().releaseConnection();
1✔
1150
        }
1151
    }
1✔
1152

1153
    /*
1154
     * Copy an input stream to an output stream.
1155
     *
1156
     * @param input The input stream to copy.
1157
     *
1158
     * @param output the output stream to write to.
1159
     *
1160
     * @throws IOException if there is trouble reading or writing to the streams.
1161
     */
1162

1163
    /**
1164
     * Copy stream.
1165
     *
1166
     * @param input  the input
1167
     * @param output the output
1168
     * @throws IOException Signals that an I/O exception has occurred.
1169
     * @deprecated replace with StreamUtil.copyContentIntoOutputStream()
1170
     */
1171
    @Deprecated(since = "2.0.0", forRemoval = true)
1172
    private static void copyStream(InputStream input, OutputStream output) throws IOException {
1173
        byte[] buffer = new byte[BUFFER_SIZE];
1✔
1174
        int len;
1175
        while ((len = input.read(buffer)) != -1) {
1✔
1176
            output.write(buffer, 0, len);
1✔
1177
        }
1178
    }
1✔
1179

1180
    /**
1181
     * @return a map of headers to be used when making requests.
1182
     */
1183
    Map<String, String> createHeaders() {
1184
        Map<String, String> headers = new HashMap<>();
1✔
1185
        headers.put("Authorization", "Bearer " + smartsheet.getAccessToken());
1✔
1186
        headers.put(HEADER_CONTENT_TYPE, JSON_CONTENT_TYPE);
1✔
1187

1188
        // Set assumed user
1189
        if (smartsheet.getAssumedUser() != null) {
1✔
1190
            headers.put("Assume-User", URLEncoder.encode(smartsheet.getAssumedUser(), StandardCharsets.UTF_8));
×
1191
        }
1192
        if (smartsheet.getChangeAgent() != null) {
1✔
1193
            headers.put("Smartsheet-Change-Agent", URLEncoder.encode(smartsheet.getChangeAgent(), StandardCharsets.UTF_8));
1✔
1194
        }
1195
        if (smartsheet.getUserAgent() != null) {
1✔
1196
            headers.put("User-Agent", smartsheet.getUserAgent());
1✔
1197
        }
1198
        return headers;
1✔
1199
    }
1200

1201
    int getResponseLogLength() {
1202
        // not cached to allow for it to be changed dynamically by client code
1203
        return Integer.getInteger(PROPERTY_RESPONSE_LOG_CHARS, 1024);
×
1204
    }
1205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc