Skip to content

Commit d073d55

Browse files
authored
Merge pull request #81 from cmgrote/master
Initial drafts of asset attachment and files APIs
2 parents 81e0612 + 4ce1dcf commit d073d55

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4853
-13
lines changed

java/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@
4848

4949
<properties>
5050
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
51-
<spring-web-version>5.3.3</spring-web-version>
51+
<spring-web-version>5.3.4</spring-web-version>
5252
<jackson-version>2.12.1</jackson-version>
5353
<jackson-databind-version>2.12.1</jackson-databind-version>
5454
<jackson-databind-nullable-version>0.2.1</jackson-databind-nullable-version>
55-
<junit-version>4.13.1</junit-version>
55+
<junit-version>4.13.2</junit-version>
5656
<surefire.plugin.version>3.0.0-M5</surefire.plugin.version>
57-
<reactor-version>3.4.2</reactor-version>
58-
<reactor-netty-version>1.0.3</reactor-netty-version>
57+
<reactor-version>3.4.3</reactor-version>
58+
<reactor-netty-version>1.0.4</reactor-netty-version>
5959
<reactor-netty-ipc-version>0.7.15.RELEASE</reactor-netty-ipc-version>
6060
<netty-version>4.1.59.Final</netty-version>
6161
<testng.version>7.3.0</testng.version>

java/src/main/java/com/ibm/watson/data/client/ApiClient.java

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515
*/
1616
package com.ibm.watson.data.client;
1717

18+
import com.fasterxml.jackson.core.type.TypeReference;
1819
import com.fasterxml.jackson.databind.DeserializationFeature;
1920
import com.fasterxml.jackson.databind.ObjectMapper;
2021
import com.ibm.watson.data.client.api.AuthorizationApi;
2122
import com.ibm.watson.data.client.auth.Authentication;
2223
import com.ibm.watson.data.client.auth.HttpBearerAuth;
2324

2425
import java.io.*;
26+
import java.net.URI;
27+
import java.nio.file.FileSystems;
2528
import java.nio.file.Files;
29+
import java.nio.file.Path;
2630
import java.nio.file.Paths;
2731
import java.security.GeneralSecurityException;
2832
import java.security.cert.X509Certificate;
@@ -41,6 +45,8 @@
4145
import org.openapitools.jackson.nullable.JsonNullableModule;
4246
import org.springframework.core.ParameterizedTypeReference;
4347
import org.springframework.core.io.FileSystemResource;
48+
import org.springframework.core.io.buffer.DataBuffer;
49+
import org.springframework.core.io.buffer.DataBufferUtils;
4450
import org.springframework.http.*;
4551
import org.springframework.http.client.reactive.ClientHttpConnector;
4652
import org.springframework.http.client.reactive.ClientHttpRequest;
@@ -90,8 +96,7 @@ private String collectionToString(Collection<?> collection) {
9096
}
9197

9298
private final HttpHeaders defaultHeaders = new HttpHeaders();
93-
private final MultiValueMap<String, String> defaultCookies =
94-
new LinkedMultiValueMap<>();
99+
private final MultiValueMap<String, String> defaultCookies = new LinkedMultiValueMap<>();
95100

96101
private String basePath = "http://localhost";
97102

@@ -105,6 +110,8 @@ private String collectionToString(Collection<?> collection) {
105110

106111
private Authentication authentication;
107112

113+
private final ObjectMapper mapper;
114+
108115
/**
109116
* Constructs a base ApiClient
110117
* @param disableSSLVerification will disable SSL verification if set to true
@@ -119,7 +126,7 @@ public ApiClient(boolean disableSSLVerification) {
119126
* @param bufferSizeInMb maximum size of buffer to allow for WebClient
120127
*/
121128
public ApiClient(boolean disableSSLVerification, int bufferSizeInMb) {
122-
ObjectMapper mapper = new ObjectMapper();
129+
mapper = new ObjectMapper();
123130
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
124131
mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
125132
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -242,6 +249,36 @@ public ApiClient setCredentials(String username, String password) {
242249
return this;
243250
}
244251

252+
/**
253+
* Save the contents of a DataBuffer into a file using the path provided.
254+
* @param path of the file to write
255+
* @param contents that should be written to the file
256+
* @return Path that was written, or null if no file was written
257+
*/
258+
public static Path saveBufferAsFile(String path, Mono<DataBuffer> contents) {
259+
final Path location = FileSystems.getDefault().getPath(path);
260+
DataBufferUtils.write(contents, location).block();
261+
return location;
262+
}
263+
264+
/**
265+
* Retrieve the contents of a DataBuffer as an object of the specified type.
266+
* Note: there is the potential for this to consume a very large amount of memory, depending on the size
267+
* of the data buffer (object) being translated.
268+
* @param contents that should be transformed into an object
269+
* @param type of object into which to transform
270+
* @param <T> of object into which to transform
271+
* @return an object of the requested type
272+
* @throws IOException if there is any problem during the transformation
273+
*/
274+
public <T> T getBufferAsObject(Mono<DataBuffer> contents, TypeReference<T> type) throws IOException {
275+
DataBuffer buffer = contents.block();
276+
if (buffer != null) {
277+
return mapper.readValue(buffer.asInputStream(true), type);
278+
}
279+
return null;
280+
}
281+
245282
private void setBearerFromUsernameAndPassword() {
246283
AuthorizationApi auth = new AuthorizationApi(this);
247284
LoginCredentials cred = new LoginCredentials();
@@ -487,9 +524,39 @@ public <T> Mono<T> invokeAPI(
487524
HttpHeaders headerParams, MultiValueMap<String, String> cookieParams,
488525
MultiValueMap<String, Object> formParams, List<MediaType> accept,
489526
MediaType contentType, ParameterizedTypeReference<T> returnType) throws RestClientException {
527+
return invokeAPI(path, method, pathParams, queryParams, body,
528+
headerParams, cookieParams, formParams, accept, contentType,
529+
returnType, false);
530+
}
531+
532+
/**
533+
* Invoke API by sending HTTP request with the given options.
534+
*
535+
* @param <T> the return type to use
536+
* @param path The sub-path of the HTTP URL
537+
* @param method The request method
538+
* @param pathParams The path parameters
539+
* @param queryParams The query parameters
540+
* @param body The request body object
541+
* @param headerParams The header parameters
542+
* @param cookieParams The cookie parameters
543+
* @param formParams The form parameters
544+
* @param accept The request's Accept header
545+
* @param contentType The request's Content-Type header
546+
* @param returnType The return type into which to deserialize the response
547+
* @param encoded true if the parameters are already URL-encoded, false (default) otherwise
548+
* @return The response body in chosen type
549+
*/
550+
public <T> Mono<T> invokeAPI(
551+
String path, HttpMethod method, Map<String, Object> pathParams,
552+
MultiValueMap<String, String> queryParams, Object body,
553+
HttpHeaders headerParams, MultiValueMap<String, String> cookieParams,
554+
MultiValueMap<String, Object> formParams, List<MediaType> accept,
555+
MediaType contentType, ParameterizedTypeReference<T> returnType,
556+
boolean encoded) throws RestClientException {
490557
final WebClient.RequestBodySpec requestBuilder = prepareRequest(
491558
path, method, pathParams, queryParams, body, headerParams, cookieParams,
492-
formParams, accept, contentType);
559+
formParams, accept, contentType, encoded);
493560
return requestBuilder.retrieve().bodyToMono(returnType);
494561
}
495562

@@ -645,6 +712,16 @@ private WebClient.RequestBodySpec prepareRequest(
645712
HttpHeaders headerParams, MultiValueMap<String, String> cookieParams,
646713
MultiValueMap<String, Object> formParams, List<MediaType> accept,
647714
MediaType contentType) {
715+
return prepareRequest(path, method, pathParams, queryParams, body,
716+
headerParams, cookieParams, formParams, accept, contentType, false);
717+
}
718+
719+
private WebClient.RequestBodySpec prepareRequest(
720+
String path, HttpMethod method, Map<String, Object> pathParams,
721+
MultiValueMap<String, String> queryParams, Object body,
722+
HttpHeaders headerParams, MultiValueMap<String, String> cookieParams,
723+
MultiValueMap<String, Object> formParams, List<MediaType> accept,
724+
MediaType contentType, boolean encoded) {
648725
updateParamsForAuth(queryParams, headerParams, cookieParams);
649726

650727
final UriComponentsBuilder builder =
@@ -653,9 +730,18 @@ private WebClient.RequestBodySpec prepareRequest(
653730
builder.queryParams(queryParams);
654731
}
655732

656-
final WebClient.RequestBodySpec requestBuilder =
657-
webClient.method(method).uri(builder.build(false).toUriString(),
658-
pathParams);
733+
// Spring / URL encoding handling is an absolute nightmare -- just expecting anyone that passes through
734+
// already-encoded query parameters to have already done their own replacement of any path parameters, as
735+
// mixing the two basically appears to be impossible without writing your own string parsing logic.
736+
WebClient.RequestBodySpec requestBuilder;
737+
if (encoded) {
738+
URI uri = builder.build(true).toUri();
739+
requestBuilder = webClient.method(method).uri(uri);
740+
} else {
741+
String uri = builder.build(false).toUriString();
742+
requestBuilder = webClient.method(method).uri(uri, pathParams);
743+
}
744+
659745
if (accept != null) {
660746
requestBuilder.accept(accept.toArray(new MediaType[accept.size()]));
661747
}

0 commit comments

Comments
 (0)