Skip to content

Commit 9ef1117

Browse files
authored
Merge branch 'master' into feature-asoc
2 parents 9da4d63 + 9a74bf5 commit 9ef1117

File tree

5 files changed

+208
-15
lines changed

5 files changed

+208
-15
lines changed

core/src/main/java/com/ibm/watson/developer_cloud/http/RequestBuilder.java

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,28 @@
1212
*/
1313
package com.ibm.watson.developer_cloud.http;
1414

15+
import java.io.InputStream;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
1519
import com.google.gson.JsonObject;
20+
import com.ibm.watson.developer_cloud.service.WatsonService;
21+
import com.ibm.watson.developer_cloud.util.GsonSingleton;
1622
import com.ibm.watson.developer_cloud.util.Validator;
23+
1724
import okhttp3.FormBody;
1825
import okhttp3.HttpUrl;
1926
import okhttp3.MediaType;
2027
import okhttp3.Request;
2128
import okhttp3.RequestBody;
2229

23-
import java.util.ArrayList;
24-
import java.util.List;
25-
2630
/**
2731
* Convenience class for constructing HTTP/HTTPS requests.
2832
*/
2933
public class RequestBuilder {
3034

3135
private enum HTTPMethod {
32-
DELETE, GET, POST, PUT
36+
DELETE, GET, POST, PUT, PATCH
3337
}
3438

3539
/**
@@ -55,8 +59,8 @@ public static RequestBuilder get(HttpUrl url) {
5559
}
5660

5761
/**
58-
* The POST request method is designed to request that a web server accept the data enclosed in the request message's
59-
* body for storage. It is often used when uploading a file or submitting a completed web form.
62+
* The POST request method is designed to request that a web server accept the data enclosed in the request
63+
* message's body for storage. It is often used when uploading a file or submitting a completed web form.
6064
*
6165
* @param url the URL
6266
*
@@ -77,6 +81,17 @@ public static RequestBuilder put(HttpUrl url) {
7781
return new RequestBuilder(HTTPMethod.PUT, url);
7882
}
7983

84+
/**
85+
* The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
86+
*
87+
* @param url the URL
88+
*
89+
* @return this
90+
*/
91+
public static RequestBuilder patch(HttpUrl url) {
92+
return new RequestBuilder(HTTPMethod.PATCH, url);
93+
}
94+
8095
/**
8196
* Creates a properly encoded HttpUrl object with no path parameters.
8297
*
@@ -146,8 +161,8 @@ private RequestBuilder(HTTPMethod method, HttpUrl url) {
146161
*
147162
* @param params the parameters
148163
* @param name the parameter name
149-
* @param value the value to set, will be obtained via {@link String#valueOf(boolean)}. If null, only the parameter is
150-
* set. It can also be a collection or array, in which case all elements are added as query parameters
164+
* @param value the value to set, will be obtained via {@link String#valueOf(boolean)}. If null, only the parameter
165+
* is set. It can also be a collection or array, in which case all elements are added as query parameters
151166
*
152167
* @return this
153168
*/
@@ -221,8 +236,8 @@ public Request build() {
221236
*/
222237
@Override
223238
public String toString() {
224-
return "RequestBuilder [method=" + method + ", formParams=" + formParams + ", headers=" + headers + ", queryParams="
225-
+ queryParams + ", httpUrl=" + httpUrl.toString() + "]";
239+
return "RequestBuilder [method=" + method + ", formParams=" + formParams + ", headers=" + headers
240+
+ ", queryParams=" + queryParams + ", httpUrl=" + httpUrl.toString() + "]";
226241
}
227242

228243
/**
@@ -277,13 +292,52 @@ public RequestBuilder body(RequestBody body) {
277292
* @return this
278293
*/
279294
public RequestBuilder bodyContent(String content, String contentType) {
280-
body = RequestBody.create(MediaType.parse(contentType), content);
295+
return body(RequestBody.create(MediaType.parse(contentType), content));
296+
}
297+
298+
/**
299+
* Sets the file content (InputStream) to the request (used with POST/PUT).
300+
*
301+
* @param stream the InputStream to read the request body content from
302+
* @param contentType the contentType associated with the data read from the InputStream
303+
* @return this
304+
*/
305+
public RequestBuilder bodyContent(InputStream stream, String contentType) {
306+
return body(InputStreamRequestBody.create(MediaType.parse(contentType), stream));
307+
}
308+
309+
/**
310+
* Sets the request body content from one of three different sources, based on the content type.
311+
*
312+
* @param contentType
313+
* the value of the "Content-Type" header associated with the outgoing request
314+
* @param jsonContent
315+
* the body content to be used if the content type indicates JSON
316+
* @param jsonPatchContent
317+
* the body content to be used if the content type indicates JsonPatch
318+
* @param nonJsonContent
319+
* the body content to be used if the content type indicates non-JSON content
320+
* @return this
321+
*/
322+
public RequestBuilder bodyContent(String contentType, Object jsonContent, Object jsonPatchContent,
323+
InputStream nonJsonContent) {
324+
if (contentType != null) {
325+
if (WatsonService.isJsonMimeType(contentType)) {
326+
this.bodyContent(
327+
GsonSingleton.getGson().toJsonTree(jsonContent).getAsJsonObject().toString(), contentType);
328+
} else if (WatsonService.isJsonPatchMimeType(contentType)) {
329+
this.bodyContent(
330+
GsonSingleton.getGson().toJsonTree(jsonPatchContent).getAsJsonObject().toString(), contentType);
331+
} else {
332+
this.bodyContent(nonJsonContent, contentType);
333+
}
334+
}
281335
return this;
282336
}
283337

284338
/**
285-
* Adds a JSON content to the request (used with POST/PUT). This will encapsulate the json into a {@link RequestBody}
286-
* encoded with UTF-8 and use {@code "application/json"} as Content-Type
339+
* Adds a JSON content to the request (used with POST/PUT). This will encapsulate the json into a
340+
* {@link RequestBody} encoded with UTF-8 and use {@code "application/json"} as Content-Type
287341
*
288342
* @param json the JsonObject json
289343
*
@@ -293,6 +347,19 @@ public RequestBuilder bodyJson(JsonObject json) {
293347
return bodyContent(json.toString(), HttpMediaType.APPLICATION_JSON);
294348
}
295349

350+
/**
351+
* Adds a JSON content to the request (used with POST/PUT/PATCH). This will encapsulate the json into a
352+
* {@link RequestBody} encoded with UTF-8 and use {@code "application/json"} as Content-Type
353+
*
354+
* @param json the JsonObject json
355+
* @param mediaType the contentType value
356+
*
357+
* @return this
358+
*/
359+
public RequestBuilder bodyJson(JsonObject json, String mediaType) {
360+
return bodyContent(json.toString(), mediaType);
361+
}
362+
296363
/**
297364
* Adds form parameters.
298365
*

core/src/main/java/com/ibm/watson/developer_cloud/service/WatsonService.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import java.util.Map;
5555
import java.util.logging.Level;
5656
import java.util.logging.Logger;
57+
import java.util.regex.Pattern;
5758

5859
/**
5960
* Watson service abstract common functionality of various Watson Services. It handle authentication and default url.
@@ -70,6 +71,7 @@ public abstract class WatsonService {
7071
private static final String BASIC = "Basic ";
7172
private static final String BEARER = "Bearer ";
7273
private static final String APIKEY_AS_USERNAME = "apikey";
74+
private static final String ICP_PREFIX = "icp-";
7375
private static final Logger LOG = Logger.getLogger(WatsonService.class.getName());
7476
private static final String AUTH_HEADER_DEPRECATION_MESSAGE = "Authenticating with the X-Watson-Authorization-Token"
7577
+ "header is deprecated. The token continues to work with Cloud Foundry services, but is not supported for "
@@ -100,6 +102,13 @@ public abstract class WatsonService {
100102
/** The Constant VERSION. */
101103
protected static final String VERSION = "version";
102104

105+
106+
// Regular expression for JSON-related mimetypes.
107+
protected static final Pattern JSON_MIME_PATTERN =
108+
Pattern.compile("(?i)application\\/((json)|(merge\\-patch\\+json))(;.*)?");
109+
protected static final Pattern JSON_PATCH_MIME_PATTERN =
110+
Pattern.compile("(?i)application\\/json\\-patch\\+json(;.*)?");
111+
103112
/**
104113
* Instantiates a new Watson service.
105114
*
@@ -126,6 +135,26 @@ public WatsonService(final String name) {
126135
client = configureHttpClient();
127136
}
128137

138+
/**
139+
* Returns true iff the specified mimeType indicates a JSON-related content type.
140+
* (e.g. application/json, application/json-patch+json, application/merge-patch+json, etc.).
141+
* @param mimeType the mimetype to consider
142+
* @return true if the mimeType indicates a JSON-related content type
143+
*/
144+
public static boolean isJsonMimeType(String mimeType) {
145+
return mimeType != null && JSON_MIME_PATTERN.matcher(mimeType).matches();
146+
}
147+
148+
/**
149+
* Returns true iff the specified mimeType indicates a "Json Patch"-related content type.
150+
* (e.g. application/json-patch+json)).
151+
* @param mimeType the mimetype to consider
152+
* @return true if the mimeType indicates a JSON-related content type
153+
*/
154+
public static boolean isJsonPatchMimeType(String mimeType) {
155+
return mimeType != null && JSON_PATCH_MIME_PATTERN.matcher(mimeType).matches();
156+
}
157+
129158
/**
130159
* Configure the {@link OkHttpClient}. This method will be called by the constructor and can be used to customize the
131160
* client that the service will use to perform the http calls.
@@ -350,7 +379,8 @@ public void setEndPoint(final String endPoint) {
350379
* @param password the password
351380
*/
352381
public void setUsernameAndPassword(final String username, final String password) {
353-
if (username.equals(APIKEY_AS_USERNAME)) {
382+
// we'll perform the token exchange for users UNLESS they're on ICP
383+
if (username.equals(APIKEY_AS_USERNAME) && !password.startsWith(ICP_PREFIX)) {
354384
IamOptions iamOptions = new IamOptions.Builder()
355385
.apiKey(password)
356386
.build();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright 2017 IBM Corp. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.ibm.watson.developer_cloud.util;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.io.InputStream;
18+
19+
/**
20+
* Helper class used by java code generated by the SDK codegen tool.
21+
*/
22+
public class StringHelper {
23+
24+
private StringHelper() {
25+
}
26+
27+
/**
28+
* Returns an InputStream that can be used to read the bytes of the specified String.
29+
* @param s the String that will back the InputStream
30+
* @return an InputStream to read the specified String
31+
*/
32+
public static InputStream toInputStream(String s) {
33+
// TODO - check to see if we need to be concerned with the encoding of the string!
34+
return new ByteArrayInputStream(s.getBytes());
35+
}
36+
}

core/src/test/java/com/ibm/watson/developer_cloud/service/AuthenticationTest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
import org.junit.Test;
44

55
import static org.junit.Assert.assertTrue;
6+
import static org.junit.Assert.assertFalse;
67

78
public class AuthenticationTest {
9+
private static final String APIKEY_USERNAME = "apikey";
810
private static final String APIKEY = "12345";
11+
private static final String ICP_APIKEY = "icp-12345";
912

1013
public class TestService extends WatsonService {
1114
private static final String SERVICE_NAME = "test";
@@ -18,7 +21,14 @@ public TestService() {
1821
@Test
1922
public void authenticateWithApiKeyAsUsername() {
2023
TestService service = new TestService();
21-
service.setUsernameAndPassword("apikey", APIKEY);
24+
service.setUsernameAndPassword(APIKEY_USERNAME, APIKEY);
2225
assertTrue(service.isTokenManagerSet());
2326
}
27+
28+
@Test
29+
public void authenticateWithIcp() {
30+
TestService service = new TestService();
31+
service.setUsernameAndPassword(APIKEY_USERNAME, ICP_APIKEY);
32+
assertFalse(service.isTokenManagerSet());
33+
}
2434
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright 2018 IBM Corp. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
package com.ibm.watson.developer_cloud.service;
14+
15+
import static org.junit.Assert.assertFalse;
16+
import static org.junit.Assert.assertTrue;
17+
18+
import org.junit.Test;
19+
20+
/**
21+
* Unit tests associated with the WatsonService core class.
22+
*
23+
*/
24+
public class WatsonServiceTest {
25+
26+
27+
@Test
28+
public void testMimeTypes() {
29+
assertTrue(WatsonService.isJsonMimeType("application/json"));
30+
assertTrue(WatsonService.isJsonMimeType("application/json; charset=utf-8"));
31+
assertTrue(WatsonService.isJsonMimeType("application/json;charset=utf-8"));
32+
assertTrue(WatsonService.isJsonMimeType("APPLICATION/JSON;charset=utf-16"));
33+
assertFalse(WatsonService.isJsonMimeType("application/notjson"));
34+
assertFalse(WatsonService.isJsonMimeType("application/json-patch+json"));
35+
assertFalse(WatsonService.isJsonMimeType("APPlication/JSON-patCH+jSoN;charset=utf-8"));
36+
assertTrue(WatsonService.isJsonPatchMimeType("APPlication/JSON-patCH+jSoN;charset=utf-8"));
37+
assertTrue(WatsonService.isJsonMimeType("application/merge-patch+json"));
38+
assertTrue(WatsonService.isJsonMimeType("application/merge-patch+json;charset=utf-8"));
39+
assertFalse(WatsonService.isJsonMimeType("application/json2-patch+json"));
40+
assertFalse(WatsonService.isJsonMimeType("application/merge-patch+json-blah"));
41+
assertFalse(WatsonService.isJsonMimeType("application/merge patch json"));
42+
43+
assertTrue(WatsonService.isJsonPatchMimeType("application/json-patch+json"));
44+
assertTrue(WatsonService.isJsonPatchMimeType("application/json-patch+json;charset=utf-8"));
45+
assertFalse(WatsonService.isJsonPatchMimeType("application/json"));
46+
assertFalse(WatsonService.isJsonPatchMimeType("APPLICATION/JsOn; charset=utf-8"));
47+
assertFalse(WatsonService.isJsonPatchMimeType("application/merge-patch+json"));
48+
assertFalse(WatsonService.isJsonPatchMimeType("application/merge-patch+json;charset=utf-8"));
49+
}
50+
}

0 commit comments

Comments
 (0)