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

hyperwallet / java-sdk / #654

01 May 2025 10:10PM CUT coverage: 97.037%. Remained the same
#654

push

grmeyer-hw-dev
Update changelog

5567 of 5737 relevant lines covered (97.04%)

67.05 hits per line

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

41.5
/src/main/java/com/hyperwallet/clientsdk/util/Request.java
1
package com.hyperwallet.clientsdk.util;
2

3
import cc.protea.util.http.BinaryResponse;
4
import cc.protea.util.http.Response;
5
import com.hyperwallet.clientsdk.util.Multipart.MultipartData;
6

7
import javax.xml.bind.DatatypeConverter;
8
import java.io.*;
9
import java.net.*;
10
import java.nio.file.Files;
11
import java.util.HashMap;
12
import java.util.List;
13
import java.util.Map;
14

15
/*
16

17
 Modified with modifications copyright Richard Stanford
18

19
 -- Original portions by Joe Ernst --
20

21
 * Copyright 2012 Joe J. Ernst
22
 * <p/>
23
 * Licensed under the Apache License, Version 2.0 (the "License");
24
 * you may not use this file except in compliance with the License.
25
 * You may obtain a copy of the License at
26
 * <p/>
27
 * http://www.apache.org/licenses/LICENSE-2.0
28
 * <p/>
29
 * Unless required by applicable law or agreed to in writing, software
30
 * distributed under the License is distributed on an "AS IS" BASIS,
31
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32
 * See the License for the specific language governing permissions and
33
 * limitations under the License.
34
 */
35

36
/**
37
 * This class represents an HTTP Request message.
38
 */
39
public class Request extends Message<Request> {
40

41
    protected final HttpURLConnection connection;
42
    private final Map<String, String> query = new HashMap<String, String>();
83✔
43
    private OutputStreamWriter writer;
44
    private URL url;
45

46
    /**
47
     * The Constructor takes the url as a String, a proxy as a Proxy, and proxy credentials as a String.
48
     *
49
     * @param url               The url parameter does not need the query string parameters if they are going to be supplied via calls to
50
     *                          {@link #addQueryParameter(String, String)}. You can, however, supply the query parameters in the URL if you wish.
51
     * @param connectionTimeout A specified timeout value, in milliseconds, to establish communications link to the resource by
52
     *                          {@link  URLConnection}.
53
     * @param readTimeout       A specified timeout, in milliseconds, for reading data from an established connection to the resource
54
     *                          by {@link  URLConnection}.
55
     * @param proxy             The Connection's Proxy value
56
     * @param proxyUsername     The Proxy username
57
     * @param proxyPassword     The Proxy password
58
     */
59
    public Request(final String url, int connectionTimeout, int readTimeout, final Proxy proxy, final String proxyUsername,
60
            final String proxyPassword) {
83✔
61
        try {
62
            this.url = new URL(url);
83✔
63
            if (proxyUsername != null && proxyPassword != null) {
83✔
64
                // NOTE: Removing Basic Auth from tunneling disabledSchemas is required in order
65
                // for Proxy Authorization to work. To prevent overriding client System Settings,
66
                // the client should set this System property themselves inside their JVM Options (1)
67
                // or their own code (2). Approaches listed below:
68
                // 1. jdk.http.auth.tunneling.disabledSchemes=
69
                // 2. System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "false");
70

71
                Authenticator authenticator = new DefaultPasswordAuthenticator(
×
72
                        proxyUsername, proxyPassword);
73
                Authenticator.setDefault(authenticator);
×
74
            }
75

76
            HttpURLConnection conn = null;
83✔
77
            if (proxy != null) {
83✔
78
                conn = (HttpURLConnection) this.url.openConnection(proxy);
12✔
79
            } else {
80
                conn = (HttpURLConnection) this.url.openConnection();
71✔
81
            }
82

83
            this.connection = conn;
83✔
84
            this.connection.setConnectTimeout(connectionTimeout);
83✔
85
            this.connection.setReadTimeout(readTimeout);
83✔
86
        } catch (IOException e) {
×
87
            throw new RuntimeException(e);
×
88
        }
83✔
89
    }
83✔
90

91
    /**
92
     * Adds a Query Parameter to a list. The list is converted to a String and appended to the URL when the Request is submitted.
93
     *
94
     * @param name  The Query Parameter's name
95
     * @param value The Query Parameter's value
96
     * @return this Request, to support chained method calls
97
     */
98
    public Request addQueryParameter(final String name, final String value) {
99
        this.query.put(name, value);
×
100
        return this;
×
101
    }
102

103
    /**
104
     * Removes the specified Query Parameter.
105
     *
106
     * @param name The name of the Query Parameter to remove
107
     * @return this Request, to support chained method calls
108
     */
109
    public Request removeQueryParameter(final String name) {
110
        this.query.remove(name);
×
111
        return this;
×
112
    }
113

114
    /**
115
     * Issues a GET to the server.
116
     *
117
     * @return The {@link Response} from the server
118
     * @throws IOException a {@link IOException}
119
     */
120
    public Response getResource() throws IOException {
121
        buildQueryString();
25✔
122
        buildHeaders();
25✔
123

124
        connection.setDoOutput(true);
25✔
125
        connection.setRequestMethod("GET");
25✔
126

127
        return readResponse();
25✔
128
    }
129

130
    /**
131
     * Issues a GET to the server.
132
     *
133
     * @return The {@link Response} from the server
134
     * @throws IOException a {@link IOException}
135
     */
136
    public BinaryResponse getBinaryResource() throws IOException {
137
        buildQueryString();
×
138
        buildHeaders();
×
139

140
        connection.setDoOutput(true);
×
141
        connection.setRequestMethod("GET");
×
142

143
        return readBinaryResponse();
×
144
    }
145

146
    /**
147
     * Issues a PUT to the server.
148
     *
149
     * @return The {@link Response} from the server
150
     * @throws IOException a {@link IOException}
151
     */
152
    public Response putResource() throws IOException {
153
        return writeResource("PUT", this.body);
15✔
154
    }
155

156
    public Response headResource() throws IOException {
157
        buildQueryString();
×
158
        buildHeaders();
×
159

160
        connection.setDoOutput(true);
×
161
        connection.setRequestMethod("HEAD");
×
162

163
        return readResponse();
×
164
    }
165

166
    public Response optionsResource() throws IOException {
167
        buildQueryString();
×
168
        buildHeaders();
×
169

170
        connection.setDoOutput(true);
×
171
        connection.setRequestMethod("OPTIONS");
×
172

173
        return readResponse();
×
174
    }
175

176
    public Response traceResource() throws IOException {
177
        buildQueryString();
×
178
        buildHeaders();
×
179

180
        connection.setDoOutput(true);
×
181
        connection.setRequestMethod("TRACE");
×
182

183
        return readResponse();
×
184
    }
185

186
    /**
187
     * Issues a POST to the server.
188
     *
189
     * @return The {@link Response} from the server
190
     * @throws IOException a {@link IOException}
191
     */
192
    public Response postResource() throws IOException {
193
        return writeResource("POST", this.body);
33✔
194
    }
195

196

197
    /**
198
     * Issues a DELETE to the server.
199
     *
200
     * @return The {@link Response} from the server
201
     * @throws IOException a {@link IOException}
202
     */
203
    public Response deleteResource() throws IOException {
204
        buildQueryString();
×
205
        buildHeaders();
×
206

207
        connection.setDoOutput(true);
×
208
        connection.setRequestMethod("DELETE");
×
209

210
        return readResponse();
×
211
    }
212

213
    /**
214
     * A private method that handles issuing POST and PUT requests
215
     *
216
     * @param method POST or PUT
217
     * @param body   The body of the Message
218
     * @return the {@link Response} from the server
219
     * @throws IOException a {@link IOException}
220
     */
221
    private Response writeResource(final String method, final String body) throws IOException {
222
        buildQueryString();
48✔
223
        buildHeaders();
48✔
224

225
        connection.setDoOutput(true);
48✔
226
        connection.setRequestMethod(method);
48✔
227

228
        writer = new OutputStreamWriter(connection.getOutputStream());
48✔
229
        writer.write(body);
41✔
230
        writer.close();
41✔
231

232
        return readResponse();
41✔
233
    }
234

235
    /**
236
     * A private method that handles reading the Responses from the server.
237
     *
238
     * @return a {@link Response} from the server.
239
     * @throws IOException a {@link IOException}
240
     */
241
    protected Response readResponse() throws IOException {
242
        Response response = new Response();
72✔
243
        response.setResponseCode(connection.getResponseCode());
72✔
244
        response.setResponseMessage(connection.getResponseMessage());
63✔
245
        response.setHeaders(connection.getHeaderFields());
63✔
246
        try {
247
            response.setBody(getStringFromStream(connection.getInputStream()));
63✔
248
        } catch (IOException e) {
33✔
249
            response.setBody(getStringFromStream(connection.getErrorStream()));
33✔
250
        }
30✔
251
        return response;
63✔
252
    }
253

254
    /**
255
     * A private method that handles reading the Responses from the server.
256
     *
257
     * @return a {@link Response} from the server.
258
     * @throws IOException a {@link IOException}
259
     */
260
    private BinaryResponse readBinaryResponse() throws IOException {
261
        BinaryResponse response = new BinaryResponse();
×
262
        response.setResponseCode(connection.getResponseCode());
×
263
        response.setResponseMessage(connection.getResponseMessage());
×
264
        response.setHeaders(connection.getHeaderFields());
×
265
        try {
266
            response.setBinaryBody(getBinaryFromStream(connection.getInputStream()));
×
267
        } catch (IOException e) {
×
268
            response.setBinaryBody(getBinaryFromStream(connection.getErrorStream()));
×
269
        }
270
        finally {
271
            connection.getInputStream().close();
×
272
            return response;
×
273
        }
274

275
    }
276

277
    private byte[] getBinaryFromStream(final InputStream is) {
278
        if (is == null) {
×
279
            return null;
×
280
        }
281
        ByteArrayOutputStream os = new ByteArrayOutputStream();
×
282
        try {
283
            byte[] buffer = new byte[0xFFFF];
×
284
            for (int len = is.read(buffer); len != -1; len = is.read(buffer)) {
×
285
                os.write(buffer, 0, len);
×
286
            }
287
            return os.toByteArray();
×
288
        } catch (IOException e) {
×
289
            return null;
×
290
        } finally {
291
            if (os != null) {
×
292
                try {
293
                    os.close();
×
294
                } catch (IOException e) {
×
295
                    // no-op
296
                }
×
297
            }
298
        }
×
299
    }
300

301
    private String getStringFromStream(final InputStream is) {
302
        if (is == null) {
63✔
303
            return null;
5✔
304
        }
305
        BufferedReader reader = null;
58✔
306
        try {
307
            reader = new BufferedReader(new InputStreamReader(is));
58✔
308
            StringBuilder builder = new StringBuilder();
58✔
309
            String line;
310
            while ((line = reader.readLine()) != null) {
178✔
311
                builder.append(line).append("\n");
120✔
312
            }
313
            return builder.toString();
116✔
314
        } catch (IOException e) {
×
315
            return null;
×
316
        } finally {
317
            if (reader != null) {
58✔
318
                try {
319
                    reader.close();
58✔
320
                } catch (IOException e) {
×
321
                    // no-op
322
                }
58✔
323
            }
324
        }
×
325
    }
326

327
    /**
328
     * A private method that loops through the query parameter Map, building a String to be appended to the URL.
329
     *
330
     * @throws MalformedURLException a {@link MalformedURLException}
331
     */
332
    protected void buildQueryString() throws MalformedURLException {
333
        StringBuilder builder = new StringBuilder();
83✔
334

335
        // Put the query parameters on the URL before issuing the request
336
        if (!query.isEmpty()) {
83✔
337
            for (Map.Entry<String, String> param : query.entrySet()) {
×
338
                builder.append(param.getKey());
×
339
                builder.append("=");
×
340
                builder.append(param.getValue());
×
341
                builder.append("&");
×
342
            }
×
343
            builder.deleteCharAt(builder.lastIndexOf("&")); // Remove the trailing ampersand
×
344
        }
345

346
        if (builder.length() > 0) {
83✔
347
            // If there was any query string at all, begin it with the question mark
348
            builder.insert(0, "?");
×
349
        }
350

351
        url = new URL(url.toString() + builder.toString());
83✔
352
    }
83✔
353

354
    /**
355
     * A private method that loops through the headers Map, putting them on the Request or Response object.
356
     */
357
    protected void buildHeaders() {
358
        if (!headers.isEmpty()) {
83✔
359
            for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
83✔
360
                List<String> values = entry.getValue();
557✔
361

362
                for (String value : values) {
557✔
363
                    connection.addRequestProperty(entry.getKey(), value);
557✔
364
                }
557✔
365
            }
557✔
366
        }
367
    }
83✔
368

369
    public Request setBodyUrlEncoded(final Map<String, String> map) {
370

371
        if (map == null) {
×
372
            this.body = null;
×
373
            return this;
×
374
        }
375

376
        StringBuilder sb = new StringBuilder();
×
377
        boolean first = true;
×
378

379
        for (Map.Entry<String, String> entry : map.entrySet()) {
×
380
            sb.append(first ? "" : "&").append(encode(entry.getKey())).append("=").append(encode(entry.getValue()));
×
381
            first = false;
×
382
        }
×
383

384
        setBody(sb.toString());
×
385
        addHeader("Content-type", "application/x-www-form-urlencoded");
×
386
        addHeader("Content-length", "" + (body.length()));
×
387

388
        return this;
×
389
    }
390

391
    public static class DefaultPasswordAuthenticator extends Authenticator {
392

393
        /**
394
         * Username
395
         */
396
        private String userName;
397

398
        /**
399
         * Password
400
         */
401
        private String password;
402

403
        public DefaultPasswordAuthenticator(String userName, String password) {
×
404
            this.userName = userName;
×
405
            this.password = password;
×
406
        }
×
407

408
        public PasswordAuthentication getPasswordAuthentication() {
409
            return (new PasswordAuthentication(userName, password.toCharArray()));
×
410
        }
411
    }
412

413
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc