• 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

93.01
/src/main/java/com/smartsheet/api/internal/http/RequestAndResponseData.java
1
package com.smartsheet.api.internal.http;
2

3
/*
4
 * #[license]
5
 * Smartsheet Java SDK
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.smartsheet.api.Trace;
24
import org.apache.http.Header;
25
import org.apache.http.client.methods.HttpRequestBase;
26

27
import java.io.IOException;
28
import java.nio.charset.StandardCharsets;
29
import java.util.Map;
30
import java.util.Set;
31
import java.util.TreeMap;
32

33
/**
34
 * a POJO from which is generated JSON from HTTP request/response pairs
35
 */
36
public class RequestAndResponseData {
37
    public abstract static class HttpPayloadData {
1✔
38
        Map<String, String> headers;
39
        String body;
40

41
        public String getBody() {
42
            return body;
×
43
        }
44

45
        public boolean hasBody() {
46
            return body != null;
1✔
47
        }
48

49
        public boolean hasHeaders() {
50
            return headers != null;
1✔
51
        }
52

53
        public Map<String, String> getHeaders() {
54
            return headers;
1✔
55
        }
56

57
        abstract static class Builder<Type extends HttpPayloadData> {
1✔
58
            public void withHeaders() {
59
                // this is seaprate from addHeader in case headers were requested but none found
60
                if (getDataObject().headers == null) {
1✔
61
                    getDataObject().headers = new TreeMap<>();
1✔
62
                }
63
            }
1✔
64

65
            public Builder addHeader(String key, String val) {
66
                withHeaders();
1✔
67
                getDataObject().headers.put(key, val);
1✔
68
                return this;
1✔
69
            }
70

71
            public Builder setBody(String body) {
72
                getDataObject().body = body;
1✔
73
                return this;
1✔
74
            }
75

76
            public abstract Type build();
77

78
            public abstract void reset();
79

80
            protected abstract Type getDataObject();
81
        }
82
    }
83

84
    public static class RequestData extends HttpPayloadData {
1✔
85
        private String command;
86

87
        public String getCommand() {
88
            return command;
1✔
89
        }
90

91
        public static class Builder extends HttpPayloadData.Builder<RequestData> {
1✔
92
            private RequestData dataObject;
93

94
            @Override
95
            public void reset() {
96
                dataObject = null;
1✔
97
            }
1✔
98

99
            @Override
100
            protected RequestData getDataObject() {
101
                if (dataObject == null) {
1✔
102
                    dataObject = new RequestData();
1✔
103
                }
104
                return dataObject;
1✔
105
            }
106

107
            public HttpPayloadData.Builder withCommand(String command) {
108
                getDataObject().command = command;
1✔
109
                return this;
1✔
110
            }
111

112
            public RequestData build() {
113
                try {
114
                    return dataObject;  // if nothing was added then nothing was built (i.e., this can be null)
1✔
115
                } finally {
116
                    reset();
1✔
117
                }
118
            }
119
        }
120
    }
121

122
    public static class ResponseData extends HttpPayloadData {
1✔
123
        private String status;
124

125
        public String getStatus() {
126
            return status;
1✔
127
        }
128

129
        public static class Builder extends HttpPayloadData.Builder<ResponseData> {
1✔
130
            private ResponseData dataObject;
131

132
            @Override
133
            public void reset() {
134
                dataObject = null;
1✔
135
            }
1✔
136

137
            @Override
138
            protected ResponseData getDataObject() {
139
                if (dataObject == null) {
1✔
140
                    dataObject = new ResponseData();
1✔
141
                }
142
                return dataObject;
1✔
143
            }
144

145
            public HttpPayloadData.Builder withStatus(String status) {
146
                getDataObject().status = status;
1✔
147
                return this;
1✔
148
            }
149

150
            public ResponseData build() {
151
                try {
152
                    // if nothing was added then nothing was built (i.e., this can be null)
153
                    return dataObject;
1✔
154
                } finally {
155
                    reset();
1✔
156
                }
157
            }
158
        }
159
    }
160

161
    private static int TRUNCATE_LENGTH = Integer.getInteger("Smartsheet.trace.truncateLen", 1024);
1✔
162

163
    public final RequestData request;
164
    public final ResponseData response;
165

166
    private RequestAndResponseData(RequestData requestData, ResponseData responseData) {
1✔
167
        request = requestData;
1✔
168
        response = responseData;
1✔
169
    }
1✔
170

171
    @Override
172
    public String toString() {
173
        return toString(false);
1✔
174
    }
175

176
    public String toString(boolean pretty) {
177
        final String EOL = pretty ? "\n" : "";
1✔
178
        final String INDENT  = pretty ? "  " : "";
1✔
179
        final String INDENT2 = INDENT + INDENT;
1✔
180
        final String INDENT3 = INDENT2 + INDENT;
1✔
181

182
        StringBuilder buf = new StringBuilder();
1✔
183
        buf.append("{").append(EOL);
1✔
184
        buf.append(INDENT).append("request:");
1✔
185
        if (request == null) {
1✔
186
            buf.append("null,").append(EOL);
×
187
        } else {
188
            buf.append("{").append(EOL);
1✔
189
            buf.append(INDENT2).append("command:'").append(request.getCommand()).append("',").append(EOL);
1✔
190
            if (request.hasHeaders()) {
1✔
191
                buf.append(INDENT2).append("headers:");
1✔
192
                if (request.getHeaders() == null) {
1✔
193
                    buf.append("null");
×
194
                } else {
195
                    buf.append("{").append(EOL);
1✔
196
                    for (Map.Entry<String, String> header : request.headers.entrySet()) {
1✔
197
                        buf.append(INDENT3).append("'").append(header.getKey()).append("':'").append(header.getValue()).append("',").append(EOL);
1✔
198
                    }
1✔
199
                    buf.append(INDENT2).append("},").append(EOL);
1✔
200
                }
201
            }
202
            if (request.hasBody()) {
1✔
203
                buf.append(INDENT2).append("body:");
1✔
204
                if (request.body == null) {
1✔
205
                    buf.append("null");
×
206
                } else {
207
                    buf.append("'").append(request.body).append("'");
1✔
208
                }
209
                buf.append(EOL);
1✔
210
            }
211
            buf.append(INDENT).append("},").append(EOL);
1✔
212
        }
213
        buf.append(INDENT).append("response:");
1✔
214
        if (response == null) {
1✔
215
            buf.append("null").append(EOL);
×
216
        } else {
217
            buf.append("{").append(EOL);
1✔
218
            buf.append(INDENT2).append("status:'").append(response.getStatus()).append("',").append(EOL);
1✔
219
            if (response.hasHeaders()) {
1✔
220
                buf.append(INDENT2).append("headers:");
1✔
221
                if (response.getHeaders() == null) {
1✔
222
                    buf.append("null");
×
223
                } else {
224
                    buf.append("{").append(EOL);
1✔
225
                    for (Map.Entry<String, String> header : response.headers.entrySet()) {
1✔
226
                        buf.append(INDENT3).append("'").append(header.getKey()).append("':'").append(header.getValue()).append("',").append(EOL);
1✔
227
                    }
1✔
228
                    buf.append(INDENT2).append("},").append(EOL);
1✔
229
                }
230
            }
231
            if (response.hasBody()) {
1✔
232
                buf.append(INDENT2).append("body:");
1✔
233
                if (response.body == null) {
1✔
234
                    buf.append("null");
×
235
                } else {
236
                    buf.append("'").append(response.body).append("'");
1✔
237
                }
238
                buf.append(EOL);
1✔
239
            }
240
            buf.append(INDENT).append("}").append(EOL);
1✔
241
        }
242
        buf.append("}");
1✔
243
        return buf.toString();
1✔
244
    }
245

246
    /**
247
     * factory method for creating a RequestAndResponseData object from request and response data with the specifid trace fields
248
     */
249
    public static RequestAndResponseData of(HttpRequestBase request, HttpEntitySnapshot requestEntity,
250
                                            HttpResponse response, HttpEntitySnapshot responseEntity,
251
                                            Set<Trace> traces)
252
            throws IOException {
253
        RequestData.Builder requestBuilder = new RequestData.Builder();
1✔
254
        ResponseData.Builder responseBuilder = new ResponseData.Builder();
1✔
255

256
        if (request != null) {
1✔
257
            requestBuilder.withCommand(request.getMethod() + " " + request.getURI());
1✔
258
            boolean binaryBody = false;
1✔
259
            if (traces.contains(Trace.RequestHeaders) && request.getAllHeaders() != null) {
1✔
260
                requestBuilder.withHeaders();
1✔
261
                for (Header header : request.getAllHeaders()) {
1✔
262
                    String headerName = header.getName();
1✔
263
                    String headerValue = header.getValue();
1✔
264
                    if ("Authorization".equals(headerName) && headerValue.length() > 0) {
1✔
265
                        headerValue = "Bearer ****" + headerValue.substring(Math.max(0, headerValue.length() - 4));
1✔
266
                    } else if ("Content-Disposition".equals(headerName)) {
1✔
267
                        binaryBody = true;
1✔
268
                    }
269
                    requestBuilder.addHeader(headerName, headerValue);
1✔
270
                }
271
            }
272
            if (requestEntity != null) {
1✔
273
                if (traces.contains(Trace.RequestBody)) {
1✔
274
                    requestBuilder.setBody(binaryBody ? binaryBody(requestEntity) : getContentAsText(requestEntity));
1✔
275
                } else if (traces.contains(Trace.RequestBodySummary)) {
1✔
276
                    requestBuilder.setBody(binaryBody ? binaryBody(requestEntity) : truncateAsNeeded(getContentAsText(requestEntity), TRUNCATE_LENGTH));
1✔
277
                }
278
            }
279
        }
280
        if (response != null) {
1✔
281
            boolean binaryBody = false;
1✔
282
            responseBuilder.withStatus(response.getStatusText());
1✔
283
            if (traces.contains(Trace.ResponseHeaders) && response.getHeaders() != null) {
1✔
284
                responseBuilder.withHeaders();
1✔
285
                for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {
1✔
286
                    String headerName = header.getKey();
1✔
287
                    String headerValue = header.getValue();
1✔
288
                    if ("Content-Disposition".equals(headerName)) {
1✔
289
                        binaryBody = true;
×
290
                    }
291
                    responseBuilder.addHeader(headerName, headerValue);
1✔
292
                }
1✔
293
            }
294
            if (responseEntity != null) {
1✔
295
                if (traces.contains(Trace.ResponseBody)) {
1✔
296
                    responseBuilder.setBody(binaryBody ? binaryBody(responseEntity) : getContentAsText(responseEntity));
1✔
297
                } else if (traces.contains(Trace.ResponseBodySummary)) {
1✔
298
                    responseBuilder.setBody(binaryBody ? binaryBody(responseEntity) : truncateAsNeeded(getContentAsText(responseEntity), TRUNCATE_LENGTH));
1✔
299
                }
300
            }
301
        }
302
        return new RequestAndResponseData(requestBuilder.build(), responseBuilder.build());
1✔
303
    }
304

305
    static String binaryBody(HttpEntitySnapshot entity) {
306
        return "**possibly-binary(type:" + entity.getContentType() + ", len:" + entity.getContentLength() + ")**";
1✔
307
    }
308

309
    public static String getContentAsText(HttpEntitySnapshot entity) {
310
        if (entity == null) {
1✔
311
            return "";
×
312
        }
313
        byte[] contentBytes = entity.getContentArray();
1✔
314
        String contentAsText;
315
        contentAsText = new String(contentBytes, StandardCharsets.UTF_8);
1✔
316
        return contentAsText;
1✔
317
    }
318

319
    public static String truncateAsNeeded(String string, int truncateLen) {
320
        if (truncateLen == -1) {
1✔
321
            return string;
×
322
        }
323
        truncateLen = Math.min(string.length(), truncateLen);
1✔
324
        String suffix = truncateLen < string.length() ? "..." : "";
1✔
325
        return string.substring(0, truncateLen) + suffix;
1✔
326
    }
327
}
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