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

smartsheet / smartsheet-java-sdk / #41

24 Aug 2023 04:59PM UTC coverage: 50.458% (+0.01%) from 50.444%
#41

push

github-actions

web-flow
Fix Checkstyle Violations in "Impl" Classes (#53)

241 of 241 new or added lines in 32 files covered. (100.0%)

3417 of 6772 relevant lines covered (50.46%)

0.5 hits per line

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

70.97
/src/main/java/com/smartsheet/api/internal/AbstractResources.java
1
package com.smartsheet.api.internal;
2

3
/*
4
 * #[license]
5
 * Smartsheet SDK for Java
6
 * %%
7
 * Copyright (C) 2023 Smartsheet
8
 * %%
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *      http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 * %[license]
21
 */
22

23
import com.fasterxml.jackson.core.JsonParseException;
24
import com.fasterxml.jackson.databind.JsonMappingException;
25
import com.smartsheet.api.AuthorizationException;
26
import com.smartsheet.api.InvalidRequestException;
27
import com.smartsheet.api.ResourceNotFoundException;
28
import com.smartsheet.api.ServiceUnavailableException;
29
import com.smartsheet.api.SmartsheetException;
30
import com.smartsheet.api.SmartsheetRestException;
31
import com.smartsheet.api.internal.http.HttpEntity;
32
import com.smartsheet.api.internal.http.HttpMethod;
33
import com.smartsheet.api.internal.http.HttpRequest;
34
import com.smartsheet.api.internal.http.HttpResponse;
35
import com.smartsheet.api.internal.json.JSONSerializerException;
36
import com.smartsheet.api.internal.util.StreamUtil;
37
import com.smartsheet.api.internal.util.Util;
38
import com.smartsheet.api.models.Attachment;
39
import com.smartsheet.api.models.CopyOrMoveRowDirective;
40
import com.smartsheet.api.models.CopyOrMoveRowResult;
41
import com.smartsheet.api.models.PagedResult;
42
import com.smartsheet.api.models.Result;
43
import org.apache.http.client.methods.CloseableHttpResponse;
44
import org.apache.http.client.methods.HttpPost;
45
import org.apache.http.entity.ContentType;
46
import org.apache.http.entity.mime.MultipartEntityBuilder;
47
import org.apache.http.impl.client.CloseableHttpClient;
48
import org.apache.http.impl.client.HttpClients;
49
import org.slf4j.Logger;
50
import org.slf4j.LoggerFactory;
51

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

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

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

76
    /** The Constant BUFFER_SIZE. */
77
    private static final int BUFFER_SIZE = 4098;
78

79
    private static final String JSON_CONTENT_TYPE = "application/json";
80
    private static final String HEADER_CONTENT_TYPE = "Content-Type";
81

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

94
        /** The error code. */
95
        int errorCode;
96

97
        /** The Exception class. */
98
        Class<? extends SmartsheetRestException> exceptionClass;
99

100
        /**
101
         * Instantiates a new error code.
102
         *
103
         * @param errorCode the error code
104
         * @param exceptionClass the Exception class
105
         */
106
        ErrorCode(int errorCode, Class<? extends SmartsheetRestException> exceptionClass) {
1✔
107
            this.errorCode = errorCode;
1✔
108
            this.exceptionClass = exceptionClass;
1✔
109
        }
1✔
110

111
        /**
112
         * Gets the error code.
113
         *
114
         * @param errorNumber the error number
115
         * @return the error code
116
         */
117
        public static ErrorCode getErrorCode(int errorNumber) {
118
            for (ErrorCode code : ErrorCode.values()) {
1✔
119
                if (code.errorCode == errorNumber) {
1✔
120
                    return code;
1✔
121
                }
122
            }
123

124
            return null;
×
125
        }
126

127
        /**
128
         * Gets the exception.
129
         *
130
         * @return the exception
131
         * @throws InstantiationException the instantiation exception
132
         * @throws IllegalAccessException the illegal access exception
133
         */
134
        public SmartsheetRestException getException() throws InstantiationException, IllegalAccessException {
135
            return exceptionClass.newInstance();
×
136
        }
137

138
        /**
139
         * Gets the exception.
140
         *
141
         * @param error the error
142
         * @return the exception
143
         * @throws SmartsheetException the smartsheet exception
144
         */
145
        public SmartsheetRestException getException(com.smartsheet.api.models.Error error) throws SmartsheetException {
146

147
            try {
148
                return exceptionClass.getConstructor(com.smartsheet.api.models.Error.class).newInstance(error);
1✔
149
            } catch (IllegalArgumentException e) {
×
150
                throw new SmartsheetException(e);
×
151
            } catch (SecurityException e) {
×
152
                throw new SmartsheetException(e);
×
153
            } catch (InstantiationException e) {
×
154
                throw new SmartsheetException(e);
×
155
            } catch (IllegalAccessException e) {
×
156
                throw new SmartsheetException(e);
×
157
            } catch (InvocationTargetException e) {
×
158
                throw new SmartsheetException(e);
×
159
            } catch (NoSuchMethodException e) {
×
160
                throw new SmartsheetException(e);
×
161
            }
162
        }
163
    }
164

165
    /**
166
     * Represents the SmartsheetImpl.
167
     *
168
     * It will be initialized in constructor and will not change afterwards.
169
     */
170
    protected final SmartsheetImpl smartsheet;
171

172
    /**
173
     * Constructor.
174
     *
175
     * @param smartsheet the smartsheet
176
     */
177
    protected AbstractResources(SmartsheetImpl smartsheet) {
1✔
178
        Util.throwIfNull(smartsheet);
1✔
179

180
        this.smartsheet = smartsheet;
1✔
181
    }
1✔
182

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

208
        if (path.isEmpty()) {
1✔
209
            com.smartsheet.api.models.Error error = new com.smartsheet.api.models.Error();
×
210
            error.setMessage("An empty path was provided.");
×
211
            throw new ResourceNotFoundException(error);
×
212
        }
213

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

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

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

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

278
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
279
        this.smartsheet.getJsonSerializer().serialize(object, objectBytesStream);
1✔
280
        HttpEntity entity = new HttpEntity();
1✔
281
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
282
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
283
        entity.setContentLength(objectBytesStream.size());
1✔
284
        request.setEntity(entity);
1✔
285

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

316
        return obj;
1✔
317
    }
318

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

349
        HttpRequest request;
350
        final String boundary = "----" + System.currentTimeMillis();
1✔
351
        CloseableHttpClient httpClient = HttpClients.createDefault();
1✔
352
        HttpPost uploadFile = createHttpPost(this.getSmartsheet().getBaseURI().resolve(path));
1✔
353

354
        try {
355
            uploadFile.setHeader(HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
1✔
356
        } catch (Exception e) {
×
357
            throw new RuntimeException(e);
×
358
        }
1✔
359

360
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
1✔
361
        builder.setBoundary(boundary);
1✔
362
        builder.addTextBody(partName, this.getSmartsheet().getJsonSerializer().serialize(object), ContentType.APPLICATION_JSON);
1✔
363
        builder.addBinaryBody("file", inputStream, ContentType.create(contentType), attachmentName);
1✔
364
        org.apache.http.HttpEntity multipart = builder.build();
1✔
365

366
        uploadFile.setEntity(multipart);
1✔
367

368
        T obj = null;
1✔
369
        //implement switch case
370
        try {
371
            CloseableHttpResponse response = httpClient.execute(uploadFile);
1✔
372
            org.apache.http.HttpEntity responseEntity = response.getEntity();
1✔
373
            obj = this.getSmartsheet().getJsonSerializer().deserializeResult(objectClass,
1✔
374
                    responseEntity.getContent()).getResult();
1✔
375
        } catch (Exception e) {
×
376
            throw new RuntimeException(e);
×
377
        }
1✔
378
        return obj;
1✔
379
    }
380

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

404
        HttpRequest request;
405
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.PUT);
1✔
406

407
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
408
        this.smartsheet.getJsonSerializer().serialize(object, objectBytesStream);
1✔
409
        HttpEntity entity = new HttpEntity();
1✔
410
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
411
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
412
        entity.setContentLength(objectBytesStream.size());
1✔
413
        request.setEntity(entity);
1✔
414

415
        T obj = null;
1✔
416
        try {
417
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
418
            switch (response.getStatusCode()) {
1✔
419
                case 200:
420
                    obj = this.smartsheet.getJsonSerializer().deserializeResult(objectClass,
1✔
421
                            response.getEntity().getContent()).getResult();
1✔
422
                    break;
1✔
423
                default:
424
                    handleError(response);
×
425
            }
426
        } finally {
427
            smartsheet.getHttpClient().releaseConnection();
1✔
428
        }
429

430
        return obj;
1✔
431
    }
432

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

454
        HttpRequest request;
455
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
×
456

457
        List<T> obj = null;
×
458
        try {
459
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
×
460
            switch (response.getStatusCode()) {
×
461
                case 200:
462
                    obj = this.smartsheet.getJsonSerializer().deserializeList(objectClass,
×
463
                            response.getEntity().getContent());
×
464
                    break;
×
465
                default:
466
                    handleError(response);
×
467
            }
468
        } finally {
469
            smartsheet.getHttpClient().releaseConnection();
×
470
        }
471

472
        return obj;
×
473
    }
474

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

488
        HttpRequest request;
489
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.GET);
1✔
490

491
        PagedResult<T> obj = null;
1✔
492
        try {
493
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
494
            switch (response.getStatusCode()) {
1✔
495
                case 200:
496
                    obj = this.smartsheet.getJsonSerializer().deserializeDataWrapper(objectClass,
1✔
497
                            response.getEntity().getContent());
1✔
498
                    break;
1✔
499
                default:
500
                    handleError(response);
×
501
            }
502
        } finally {
503
            smartsheet.getHttpClient().releaseConnection();
1✔
504
        }
505

506
        return obj;
1✔
507
    }
508

509
    /**
510
     * Delete a resource from Smartsheet REST API.
511
     *
512
     * Exceptions:
513
     *   IllegalArgumentException : if any argument is null, or path is empty string
514
     *   InvalidRequestException : if there is any problem with the REST API request
515
     *   AuthorizationException : if there is any problem with the REST API authorization(access token)
516
     *   ResourceNotFoundException : if the resource can not be found
517
     *   ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
518
     *   SmartsheetRestException : if there is any other REST API related error occurred during the operation
519
     *   SmartsheetException : if there is any other error occurred during the operation
520
     *
521
     * @param <T> the generic type
522
     * @param path the relative path of the resource
523
     * @param objectClass the resource object class
524
     * @throws SmartsheetException the smartsheet exception
525
     */
526
    protected <T> void deleteResource(String path, Class<T> objectClass) throws SmartsheetException {
527
        Util.throwIfNull(path, objectClass);
1✔
528
        Util.throwIfEmpty(path);
1✔
529

530
        HttpRequest request;
531
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.DELETE);
1✔
532

533
        try {
534
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
535
            switch (response.getStatusCode()) {
1✔
536
                case 200:
537
                    this.smartsheet.getJsonSerializer().deserializeResult(objectClass,
1✔
538
                            response.getEntity().getContent());
1✔
539
                    break;
1✔
540
                default:
541
                    handleError(response);
×
542
            }
543
        } finally {
544
            smartsheet.getHttpClient().releaseConnection();
1✔
545
        }
546
    }
1✔
547

548
    /**
549
     * Delete resources and return a list from Smartsheet REST API.
550
     *
551
     * Exceptions:
552
     *   IllegalArgumentException : if any argument is null, or path is empty string
553
     *   InvalidRequestException : if there is any problem with the REST API request
554
     *   AuthorizationException : if there is any problem with the REST API authorization(access token)
555
     *   ResourceNotFoundException : if the resource can not be found
556
     *   ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
557
     *   SmartsheetRestException : if there is any other REST API related error occurred during the operation
558
     *   SmartsheetException : if there is any other error occurred during the operation
559
     *
560
     * @param <T> the generic type
561
     * @param path the relative path of the resource
562
     * @param objectClass the resource object class
563
     * @return List of ids deleted
564
     * @throws SmartsheetException the smartsheet exception
565
     */
566
    protected <T> List<T> deleteListResources(String path, Class<T> objectClass) throws SmartsheetException {
567
        Util.throwIfNull(path, objectClass);
1✔
568
        Util.throwIfEmpty(path);
1✔
569

570
        Result<List<T>> obj = null;
1✔
571
        HttpRequest request;
572
        request = createHttpRequest(smartsheet.getBaseURI().resolve(path), HttpMethod.DELETE);
1✔
573
        try {
574
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
575
            switch (response.getStatusCode()) {
1✔
576
                case 200:
577
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(objectClass,
1✔
578
                            response.getEntity().getContent());
1✔
579
                    break;
1✔
580
                default:
581
                    handleError(response);
×
582
            }
583
        } finally {
584
            smartsheet.getHttpClient().releaseConnection();
1✔
585
        }
586
        return obj.getResult();
1✔
587
    }
588

589
    /**
590
     * Post an object to Smartsheet REST API and receive a list of objects from response.
591
     *
592
     * Parameters: - path : the relative path of the resource collections - objectToPost : the object to post -
593
     * objectClassToReceive : the resource object class to receive
594
     *
595
     * Returns: the object list
596
     *
597
     * Exceptions:
598
     *   IllegalArgumentException : if any argument is null, or path is empty string
599
     *   InvalidRequestException : if there is any problem with the REST API request
600
     *   AuthorizationException : if there is any problem with the REST API authorization(access token)
601
     *   ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
602
     *   SmartsheetRestException : if there is any other REST API related error occurred during the operation
603
     *   SmartsheetException : if there is any other error occurred during the operation
604
     *
605
     * @param <T> the generic type
606
     * @param <S> the generic type
607
     * @param path the path
608
     * @param objectToPost the object to post
609
     * @param objectClassToReceive the object class to receive
610
     * @return the list
611
     * @throws SmartsheetException the smartsheet exception
612
     */
613
    protected <T, S> List<S> postAndReceiveList(String path, T objectToPost, Class<S> objectClassToReceive) throws SmartsheetException {
614
        Util.throwIfNull(path, objectToPost, objectClassToReceive);
1✔
615
        Util.throwIfEmpty(path);
1✔
616

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

619
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
620
        this.smartsheet.getJsonSerializer().serialize(objectToPost, objectBytesStream);
1✔
621
        HttpEntity entity = new HttpEntity();
1✔
622
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
623
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
624
        entity.setContentLength(objectBytesStream.size());
1✔
625
        request.setEntity(entity);
1✔
626

627
        List<S> obj = null;
1✔
628
        try {
629
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
630
            switch (response.getStatusCode()) {
1✔
631
                case 200:
632
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(objectClassToReceive,
1✔
633
                            response.getEntity().getContent()).getResult();
1✔
634
                    break;
1✔
635
                default:
636
                    handleError(response);
×
637
            }
638
        } finally {
639
            smartsheet.getHttpClient().releaseConnection();
1✔
640
        }
641

642
        return obj;
1✔
643
    }
644

645
    /**
646
     * Post an object to Smartsheet REST API and receive a CopyOrMoveRowResult object from response.
647
     *
648
     * Parameters: - path : the relative path of the resource collections - objectToPost : the object to post -
649
     *
650
     * Returns: the object
651
     *
652
     * Exceptions:
653
     *   IllegalArgumentException : if any argument is null, or path is empty string
654
     *   InvalidRequestException : if there is any problem with the REST API request
655
     *   AuthorizationException : if there is any problem with the REST API authorization(access token)
656
     *   ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
657
     *   SmartsheetRestException : if there is any other REST API related error occurred during the operation
658
     *   SmartsheetException : if there is any other error occurred during the operation
659
     *
660
     * @param path the path
661
     * @param objectToPost the object to post
662
     * @return the result object
663
     * @throws SmartsheetException the smartsheet exception
664
     */
665
    protected CopyOrMoveRowResult postAndReceiveRowObject(String path, CopyOrMoveRowDirective objectToPost) throws SmartsheetException {
666
        Util.throwIfNull(path, objectToPost);
1✔
667
        Util.throwIfEmpty(path);
1✔
668

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

671
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
672
        this.smartsheet.getJsonSerializer().serialize(objectToPost, objectBytesStream);
1✔
673
        HttpEntity entity = new HttpEntity();
1✔
674
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
675
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
676
        entity.setContentLength(objectBytesStream.size());
1✔
677
        request.setEntity(entity);
1✔
678

679
        CopyOrMoveRowResult obj = null;
1✔
680
        try {
681
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
682
            switch (response.getStatusCode()) {
1✔
683
                case 200:
684
                    obj = this.smartsheet.getJsonSerializer().deserializeCopyOrMoveRow(
1✔
685
                            response.getEntity().getContent());
1✔
686
                    break;
1✔
687
                default:
688
                    handleError(response);
×
689
            }
690
        } finally {
691
            smartsheet.getHttpClient().releaseConnection();
1✔
692
        }
693

694
        return obj;
1✔
695
    }
696

697
    /**
698
     * Put an object to Smartsheet REST API and receive a list of objects from response.
699
     * @param <T> the generic type
700
     * @param <S> the generic type
701
     * @param path the relative path of the resource collections
702
     * @param objectToPut the object to put
703
     * @param objectClassToReceive the resource object class to receive
704
     * @return the object list
705
     * @throws IllegalArgumentException : if any argument is null, or path is empty string
706
     * @throws InvalidRequestException : if there is any problem with the REST API request
707
     * @throws AuthorizationException : if there is any problem with the REST API authorization(access token)
708
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
709
     * @throws SmartsheetRestException : if there is any other REST API related error occurred during the operation
710
     * @throws SmartsheetException : if there is any other error occurred during the operation
711
     */
712
    protected <T, S> List<S> putAndReceiveList(String path, T objectToPut, Class<S> objectClassToReceive)
713
            throws SmartsheetException {
714
        Util.throwIfNull(path, objectToPut, objectClassToReceive);
1✔
715
        Util.throwIfEmpty(path);
1✔
716

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

719
        ByteArrayOutputStream objectBytesStream = new ByteArrayOutputStream();
1✔
720
        this.smartsheet.getJsonSerializer().serialize(objectToPut, objectBytesStream);
1✔
721
        HttpEntity entity = new HttpEntity();
1✔
722
        entity.setContentType(JSON_CONTENT_TYPE);
1✔
723
        entity.setContent(new ByteArrayInputStream(objectBytesStream.toByteArray()));
1✔
724
        entity.setContentLength(objectBytesStream.size());
1✔
725
        request.setEntity(entity);
1✔
726

727
        List<S> obj = null;
1✔
728
        try {
729
            HttpResponse response = this.smartsheet.getHttpClient().request(request);
1✔
730
            switch (response.getStatusCode()) {
1✔
731
                case 200:
732
                    obj = this.smartsheet.getJsonSerializer().deserializeListResult(
1✔
733
                            objectClassToReceive, response.getEntity().getContent()).getResult();
1✔
734
                    break;
1✔
735
                default:
736
                    handleError(response);
×
737
            }
738
        } finally {
739
            smartsheet.getHttpClient().releaseConnection();
1✔
740
        }
741

742
        return obj;
1✔
743
    }
744

745
    /**
746
     * Create an HttpRequest.
747
     * @param uri    the URI
748
     * @param method the HttpMethod
749
     * @return the http request
750
     */
751
    protected HttpRequest createHttpRequest(URI uri, HttpMethod method) {
752
        HttpRequest request = new HttpRequest();
1✔
753
        request.setUri(uri);
1✔
754
        request.setMethod(method);
1✔
755

756
        // Set authorization header
757
        request.setHeaders(createHeaders());
1✔
758

759
        return request;
1✔
760
    }
761

762
    protected HttpPost createHttpPost(URI uri) {
763
        HttpPost httpPost = new HttpPost(uri);
1✔
764
        Map<String, String> headers = createHeaders();
1✔
765
        for (Map.Entry<String, String> entry : headers.entrySet()) {
1✔
766
            httpPost.addHeader(entry.getKey(), entry.getValue());
1✔
767
        }
1✔
768
        return httpPost;
1✔
769
    }
770

771
    /**
772
     * Attach a file
773
     */
774
    public Attachment attachFile(String url, InputStream inputStream, String contentType, long contentLength, String attachmentName)
775
            throws SmartsheetException {
776
        Util.throwIfNull(inputStream, contentType);
1✔
777
        HttpRequest request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(url), HttpMethod.POST);
1✔
778
        request.getHeaders().put(
1✔
779
                "Content-Disposition",
780
                "attachment; filename=\"" + URLEncoder.encode(attachmentName, StandardCharsets.UTF_8) + "\""
1✔
781
        );
782
        HttpEntity entity = new HttpEntity();
1✔
783
        entity.setContentType(contentType);
1✔
784
        entity.setContent(new LengthEnforcingInputStream(inputStream, contentLength));
1✔
785
        entity.setContentLength(contentLength);
1✔
786
        request.setEntity(entity);
1✔
787

788
        Attachment attachment = null;
1✔
789
        try {
790
            HttpResponse response = this.getSmartsheet().getHttpClient().request(request);
1✔
791
            switch (response.getStatusCode()) {
1✔
792
                case 200:
793
                    attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
1✔
794
                            response.getEntity().getContent()).getResult();
1✔
795
                    break;
1✔
796
                default:
797
                    handleError(response);
×
798
            }
799
        } finally {
800
            this.getSmartsheet().getHttpClient().releaseConnection();
1✔
801
        }
802

803
        return attachment;
1✔
804
    }
805

806
    /**
807
     * Create a multipart upload request.
808
     *
809
     * @param url the url
810
     * @param t the object to create
811
     * @param partName the name of the part
812
     * @param inputstream the file inputstream
813
     * @param contentType the type of the file to be attached
814
     * @return the http request
815
     * @throws SmartsheetException may be thrown in the method
816
     */
817
    public <T> Attachment attachFile(String url, T t, String partName, InputStream inputstream, String contentType, String attachmentName)
818
            throws SmartsheetException {
819
        Util.throwIfNull(inputstream, contentType);
×
820
        Attachment attachment = null;
×
821
        final String boundary = "----" + System.currentTimeMillis();
×
822

823
        CloseableHttpClient httpClient = HttpClients.createDefault();
×
824
        HttpPost uploadFile = createHttpPost(this.getSmartsheet().getBaseURI().resolve(url));
×
825

826
        try {
827
            uploadFile.setHeader(HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
×
828
        } catch (Exception e) {
×
829
            throw new RuntimeException(e);
×
830
        }
×
831

832
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
×
833
        builder.setBoundary(boundary);
×
834
        builder.addTextBody(partName, this.getSmartsheet().getJsonSerializer().serialize(t), ContentType.APPLICATION_JSON);
×
835
        builder.addBinaryBody("file", inputstream, ContentType.create(contentType), attachmentName);
×
836
        org.apache.http.HttpEntity multipart = builder.build();
×
837

838
        uploadFile.setEntity(multipart);
×
839

840
        try {
841
            CloseableHttpResponse response = httpClient.execute(uploadFile);
×
842
            org.apache.http.HttpEntity responseEntity = response.getEntity();
×
843
            attachment = this.getSmartsheet().getJsonSerializer().deserializeResult(Attachment.class,
×
844
                    responseEntity.getContent()).getResult();
×
845
        } catch (Exception e) {
×
846
            throw new RuntimeException(e);
×
847
        }
×
848
        return attachment;
×
849
    }
850

851
    /**
852
     * Handles an error HttpResponse (non-200) returned by Smartsheet REST API.
853
     * @param response the HttpResponse
854
     * @throws SmartsheetException the smartsheet exception
855
     * @throws SmartsheetRestException : the exception corresponding to the error
856
     */
857
    protected void handleError(HttpResponse response) throws SmartsheetException {
858

859
        com.smartsheet.api.models.Error error;
860
        try {
861
            error = this.smartsheet.getJsonSerializer().deserialize(
1✔
862
                    com.smartsheet.api.models.Error.class, response.getEntity().getContent());
1✔
863
        } catch (JsonParseException e) {
×
864
            throw new SmartsheetException(e);
×
865
        } catch (JsonMappingException e) {
×
866
            throw new SmartsheetException(e);
×
867
        } catch (IOException e) {
×
868
            throw new SmartsheetException(e);
×
869
        }
1✔
870

871
        ErrorCode code = ErrorCode.getErrorCode(response.getStatusCode());
1✔
872

873
        if (code == null) {
1✔
874
            throw new SmartsheetRestException(error);
×
875
        }
876

877
        try {
878
            throw code.getException(error);
1✔
879
        } catch (IllegalArgumentException e) {
×
880
            throw new SmartsheetException(e);
×
881
        } catch (SecurityException e) {
×
882
            throw new SmartsheetException(e);
×
883
        }
884
    }
885

886
    /**
887
     * Gets the smartsheet.
888
     *
889
     * @return the smartsheet
890
     */
891
    public SmartsheetImpl getSmartsheet() {
892
        return smartsheet;
1✔
893
    }
894

895
    /**
896
     * Get a sheet as a file.
897
     * @param path the path
898
     * @param fileType the output file type
899
     * @param outputStream the OutputStream to which the file will be written
900
     * @throws InvalidRequestException : if there is any problem with the REST API request
901
     * @throws AuthorizationException : if there is any problem with the REST API authorization(access token)
902
     * @throws ResourceNotFoundException : if the resource can not be found
903
     * @throws ServiceUnavailableException : if the REST API service is not available (possibly due to rate limiting)
904
     * @throws SmartsheetRestException : if there is any other REST API related error occurred during the operation
905
     * @throws SmartsheetException : if there is any other error occurred during the operation
906
     */
907
    public void getResourceAsFile(String path, String fileType, OutputStream outputStream)
908
            throws SmartsheetException {
909
        Util.throwIfNull(outputStream, fileType);
1✔
910

911
        HttpRequest request;
912
        request = createHttpRequest(this.getSmartsheet().getBaseURI().resolve(path), HttpMethod.GET);
1✔
913
        request.getHeaders().put("Accept", fileType);
1✔
914

915
        try {
916
            HttpResponse response = getSmartsheet().getHttpClient().request(request);
1✔
917

918
            switch (response.getStatusCode()) {
1✔
919
                case 200:
920
                    try {
921
                        copyStream(response.getEntity().getContent(), outputStream);
1✔
922
                    } catch (IOException e) {
×
923
                        throw new SmartsheetException(e);
×
924
                    }
1✔
925
                    break;
926
                default:
927
                    handleError(response);
×
928
            }
929
        } finally {
930
            getSmartsheet().getHttpClient().releaseConnection();
1✔
931
        }
932
    }
1✔
933

934
    /*
935
     * Copy an input stream to an output stream.
936
     *
937
     * @param input The input stream to copy.
938
     *
939
     * @param output the output stream to write to.
940
     *
941
     * @throws IOException if there is trouble reading or writing to the streams.
942
     */
943
    /**
944
     * Copy stream.
945
     *
946
     * @param input the input
947
     * @param output the output
948
     * @throws IOException Signals that an I/O exception has occurred.
949
     * @deprecated replace with StreamUtil.copyContentIntoOutputStream()
950
     */
951
    @Deprecated
952
    private static void copyStream(InputStream input, OutputStream output) throws IOException {
953
        byte[] buffer = new byte[BUFFER_SIZE];
1✔
954
        int len;
955
        while ((len = input.read(buffer)) != -1) {
1✔
956
            output.write(buffer, 0, len);
1✔
957
        }
958
    }
1✔
959

960
    /**
961
     * @return a map of headers to be used when making requests.
962
     */
963
    Map<String, String> createHeaders() {
964
        Map<String, String> headers = new HashMap<>();
1✔
965
        headers.put("Authorization", "Bearer " + smartsheet.getAccessToken());
1✔
966
        headers.put(HEADER_CONTENT_TYPE, JSON_CONTENT_TYPE);
1✔
967

968
        // Set assumed user
969
        if (smartsheet.getAssumedUser() != null) {
1✔
970
            headers.put("Assume-User", URLEncoder.encode(smartsheet.getAssumedUser(), StandardCharsets.UTF_8));
×
971
        }
972
        if (smartsheet.getChangeAgent() != null) {
1✔
973
            headers.put("Smartsheet-Change-Agent", URLEncoder.encode(smartsheet.getChangeAgent(), StandardCharsets.UTF_8));
1✔
974
        }
975
        if (smartsheet.getUserAgent() != null) {
1✔
976
            headers.put("User-Agent", smartsheet.getUserAgent());
1✔
977
        }
978
        return headers;
1✔
979
    }
980

981
    int getResponseLogLength() {
982
        // not cached to allow for it to be changed dynamically by client code
983
        return Integer.getInteger(PROPERTY_RESPONSE_LOG_CHARS, 1024);
1✔
984
    }
985
}
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

© 2026 Coveralls, Inc