OkHttp client (#416)
* Created stub factory, client and test using jaxrs as a template * OkHttp client, request and response partially implemented * OkHttp client now adds sensible default headers to requests * Creating an OkHttp byte request is now implemented * OkHttp query parameter requests now supported * Refactored tests, no longer comparing case for charsets * Added proxy support to okhttpclientfactory Re-enabled no-fhir-context test * Fixed no-context test - expected exception message is now generic * fixed some content type comparisons * Removing trailing question marks from URLs as OkHttp doesn't do this automatically (like JaxRs) * Fixed NPE when content-type header doesn't exist * Correct HTTP method is now set on OkHttp requests (PUT, POST, UPDATE, etc.) * Removed support for getRequestBodyFromStream - wasn't implemented correctly * Added response buffering * Updated test in light of changes pulled in from master * Extract method refactors in okhttprestfulclient * Implemented binary request with the OkHttp client * Extracted out a generic string utils class * Added relevant file and class headers * Reformatted code * Implemented getHttpClient(serverBase) in OkHttpRestfulClientFactory * Renamed fields and parameters to be consistent with the rest of the project * Reformat OkHttpClientDstu2Test (removes extraneous blank lines etc.) * Removed additional blank lines in test * Copied missing bundle_orion.xml to OkHttp test resources
This commit is contained in:
parent
681f4e153d
commit
06b9059a87
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hapi-fhir-okhttp</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HAPI FHIR OkHttp Client</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- HAPI DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- conformance profile -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Unit test dependencies -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-servlet-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-jetty-http</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-moxy</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,183 @@
|
|||
package ca.uhn.fhir.okhttp.client;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.HttpClientUtil;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import okhttp3.*;
|
||||
import okhttp3.internal.Version;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.*;
|
||||
|
||||
/**
|
||||
* A Http Request based on OkHttp. This is an adapter around the class
|
||||
* {@link OkHttpClient}
|
||||
*
|
||||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||
*/
|
||||
public class OkHttpRestfulClient implements IHttpClient {
|
||||
|
||||
private OkHttpClient myClient;
|
||||
private StringBuilder myUrl;
|
||||
private Map<String, List<String>> myIfNoneExistParams;
|
||||
private String myIfNoneExistString;
|
||||
private RequestTypeEnum myRequestType;
|
||||
private List<Header> myHeaders;
|
||||
private OkHttpRestfulRequest myRequest;
|
||||
|
||||
public OkHttpRestfulClient(OkHttpClient theClient,
|
||||
StringBuilder theUrl,
|
||||
Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString,
|
||||
RequestTypeEnum theRequestType,
|
||||
List<Header> theHeaders) {
|
||||
myClient = theClient;
|
||||
myUrl = theUrl;
|
||||
myIfNoneExistParams = theIfNoneExistParams;
|
||||
myIfNoneExistString = theIfNoneExistString;
|
||||
myRequestType = theRequestType;
|
||||
myHeaders = theHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createByteRequest(FhirContext theContext, String theContents, String theContentType, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, createPostBody(theContents, theContentType));
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
private void initBaseRequest(FhirContext theContext, EncodingEnum theEncoding, RequestBody body) {
|
||||
String sanitisedUrl = withTrailingQuestionMarkRemoved(myUrl.toString());
|
||||
myRequest = new OkHttpRestfulRequest(myClient, sanitisedUrl, myRequestType, body);
|
||||
addHeadersToRequest(myRequest, theEncoding, theContext);
|
||||
}
|
||||
|
||||
private RequestBody createPostBody(String theContents, String theContentType) {
|
||||
return RequestBody.create(MediaType.parse(theContentType), theContents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createParamRequest(FhirContext theContext, Map<String, List<String>> theParams, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, getFormBodyFromParams(theParams));
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
private RequestBody getFormBodyFromParams(Map<String, List<String>> queryParams) {
|
||||
FormBody.Builder formBuilder = new FormBody.Builder();
|
||||
for (Map.Entry<String, List<String>> paramEntry : queryParams.entrySet()) {
|
||||
for (String value : paramEntry.getValue()) {
|
||||
formBuilder.add(paramEntry.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
return formBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createBinaryRequest(FhirContext theContext, IBaseBinary theBinary) {
|
||||
initBaseRequest(theContext, null, createPostBody(theBinary.getContent(), theBinary.getContentType()));
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
private RequestBody createPostBody(byte[] theContents, String theContentType) {
|
||||
return RequestBody.create(MediaType.parse(theContentType), theContents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, null);
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
private void addHeadersToRequest(OkHttpRestfulRequest theHttpRequest, EncodingEnum theEncoding, FhirContext theContext) {
|
||||
if (myHeaders != null) {
|
||||
for (Header next : myHeaders) {
|
||||
theHttpRequest.addHeader(next.getName(), next.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
addUserAgentHeader(theHttpRequest, theContext);
|
||||
addAcceptCharsetHeader(theHttpRequest);
|
||||
addAcceptHeader(theHttpRequest, theEncoding);
|
||||
addIfNoneExistHeader(theHttpRequest);
|
||||
}
|
||||
|
||||
private void addUserAgentHeader(OkHttpRestfulRequest theHttpRequest, FhirContext theContext) {
|
||||
theHttpRequest.addHeader("User-Agent", HttpClientUtil.createUserAgentString(theContext, Version.userAgent()));
|
||||
}
|
||||
|
||||
private void addAcceptCharsetHeader(OkHttpRestfulRequest theHttpRequest) {
|
||||
theHttpRequest.addHeader("Accept-Charset", "utf-8");
|
||||
}
|
||||
|
||||
private void addAcceptHeader(OkHttpRestfulRequest theHttpRequest, EncodingEnum theEncoding) {
|
||||
Request.Builder builder = theHttpRequest.getRequest();
|
||||
|
||||
if (theEncoding == null) {
|
||||
builder.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY);
|
||||
} else if (theEncoding == EncodingEnum.JSON) {
|
||||
builder.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON);
|
||||
} else if (theEncoding == EncodingEnum.XML) {
|
||||
builder.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML);
|
||||
}
|
||||
}
|
||||
|
||||
private void addIfNoneExistHeader(IHttpRequest result) {
|
||||
if (myIfNoneExistParams != null) {
|
||||
addIfNoneExistHeaderFromParams(result, myIfNoneExistParams);
|
||||
} else if (myIfNoneExistString != null) {
|
||||
addIfNoneExistHeaderFromString(result, myIfNoneExistString);
|
||||
}
|
||||
}
|
||||
|
||||
private void addIfNoneExistHeaderFromString(IHttpRequest result, String ifNoneExistString) {
|
||||
StringBuilder sb = newHeaderBuilder(myUrl);
|
||||
boolean shouldAddQuestionMark = !hasQuestionMark(sb);
|
||||
sb.append(shouldAddQuestionMark ? '?' : '&');
|
||||
sb.append(everythingAfterFirstQuestionMark(ifNoneExistString));
|
||||
result.addHeader(Constants.HEADER_IF_NONE_EXIST, sb.toString());
|
||||
}
|
||||
|
||||
private void addIfNoneExistHeaderFromParams(IHttpRequest result, Map<String, List<String>> ifNoneExistParams) {
|
||||
StringBuilder sb = newHeaderBuilder(myUrl);
|
||||
boolean shouldAddInitialQuestionMark = !hasQuestionMark(sb);
|
||||
BaseHttpClientInvocation.appendExtraParamsWithQuestionMark(ifNoneExistParams, sb, shouldAddInitialQuestionMark);
|
||||
result.addHeader(Constants.HEADER_IF_NONE_EXIST, sb.toString());
|
||||
}
|
||||
|
||||
public static StringBuilder newHeaderBuilder(StringBuilder baseUrl) {
|
||||
StringBuilder sb = new StringBuilder(baseUrl);
|
||||
if (endsWith(baseUrl, '/')) {
|
||||
deleteLastCharacter(sb);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package ca.uhn.fhir.okhttp.client;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A Restful client factory based on OkHttp.
|
||||
*
|
||||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||
*/
|
||||
public class OkHttpRestfulClientFactory extends RestfulClientFactory {
|
||||
|
||||
private OkHttpClient myNativeClient;
|
||||
|
||||
public OkHttpRestfulClientFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OkHttpRestfulClientFactory(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IHttpClient getHttpClient(String theServerBase) {
|
||||
return new OkHttpRestfulClient(getNativeClient(), new StringBuilder(theServerBase), null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetHttpClient() {
|
||||
myNativeClient = null;
|
||||
}
|
||||
|
||||
public synchronized OkHttpClient getNativeClient() {
|
||||
if (myNativeClient == null) {
|
||||
myNativeClient = new OkHttpClient();
|
||||
}
|
||||
|
||||
return myNativeClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpClient getHttpClient(StringBuilder theUrl,
|
||||
Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString,
|
||||
RequestTypeEnum theRequestType,
|
||||
List<Header> theHeaders) {
|
||||
return new OkHttpRestfulClient(getNativeClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only accepts clients of type {@link OkHttpClient}
|
||||
*
|
||||
* @param okHttpClient
|
||||
*/
|
||||
@Override
|
||||
public void setHttpClient(Object okHttpClient) {
|
||||
myNativeClient = (OkHttpClient) okHttpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProxy(String theHost, Integer thePort) {
|
||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(theHost, thePort));
|
||||
OkHttpClient.Builder builder = getNativeClient().newBuilder().proxy(proxy);
|
||||
setHttpClient(builder.build());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package ca.uhn.fhir.okhttp.client;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapter for building an OkHttp-specific request.
|
||||
*
|
||||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||
*/
|
||||
public class OkHttpRestfulRequest implements IHttpRequest {
|
||||
|
||||
private final Request.Builder myRequestBuilder;
|
||||
private OkHttpClient myClient;
|
||||
private String myUrl;
|
||||
private RequestTypeEnum myRequestTypeEnum;
|
||||
private RequestBody myRequestBody;
|
||||
|
||||
public OkHttpRestfulRequest(OkHttpClient theClient, String theUrl, RequestTypeEnum theRequestTypeEnum, RequestBody theRequestBody) {
|
||||
myClient = theClient;
|
||||
myUrl = theUrl;
|
||||
myRequestTypeEnum = theRequestTypeEnum;
|
||||
myRequestBody = theRequestBody;
|
||||
|
||||
myRequestBuilder = new Request.Builder().url(theUrl);
|
||||
}
|
||||
|
||||
public Request.Builder getRequest() {
|
||||
return myRequestBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String theName, String theValue) {
|
||||
myRequestBuilder.addHeader(theName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpResponse execute() throws IOException {
|
||||
myRequestBuilder.method(getHttpVerbName(), myRequestBody);
|
||||
Call call = myClient.newCall(myRequestBuilder.build());
|
||||
return new OkHttpRestfulResponse(call.execute());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAllHeaders() {
|
||||
return myRequestBuilder.build().headers().toMultimap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestBodyFromStream() throws IOException {
|
||||
// returning null to indicate this is not supported, as documented in IHttpRequest's contract
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpVerbName() {
|
||||
return myRequestTypeEnum.name();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package ca.uhn.fhir.okhttp.client;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wraps an OkHttp {@link Response}
|
||||
*
|
||||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||
*/
|
||||
public class OkHttpRestfulResponse implements IHttpResponse {
|
||||
|
||||
private Response myResponse;
|
||||
private boolean myEntityBuffered = false;
|
||||
private byte[] myEntityBytes;
|
||||
|
||||
public OkHttpRestfulResponse(Response theResponse) {
|
||||
this.myResponse = theResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() {
|
||||
return myResponse.code();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResponse() {
|
||||
return myResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
String contentType = myResponse.header(Constants.HEADER_CONTENT_TYPE);
|
||||
if (contentType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MediaType mediaType = MediaType.parse(contentType);
|
||||
if (mediaType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return typeAndSubtypeOnly(mediaType).toString();
|
||||
}
|
||||
|
||||
private MediaType typeAndSubtypeOnly(MediaType input) {
|
||||
return MediaType.parse(input.type() + "/" + input.subtype());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAllHeaders() {
|
||||
return myResponse.headers().toMultimap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusInfo() {
|
||||
return myResponse.message();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader createReader() throws IOException {
|
||||
if (!myEntityBuffered && myResponse.body() == null) {
|
||||
return new StringReader("");
|
||||
} else {
|
||||
return new InputStreamReader(readEntity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream readEntity() throws IOException {
|
||||
if (this.myEntityBuffered) {
|
||||
return new ByteArrayInputStream(myEntityBytes);
|
||||
} else if (myResponse.body() != null) {
|
||||
return myResponse.body().byteStream();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
myResponse.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bufferEntitity() throws IOException {
|
||||
if (myEntityBuffered) {
|
||||
return;
|
||||
}
|
||||
InputStream responseEntity = readEntity();
|
||||
if (responseEntity != null) {
|
||||
myEntityBuffered = true;
|
||||
try {
|
||||
myEntityBytes = IOUtils.toByteArray(responseEntity);
|
||||
} catch (IllegalStateException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.okhttp.utils;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
public class UrlStringUtils {
|
||||
|
||||
public static String withTrailingQuestionMarkRemoved(String input) {
|
||||
return input.replaceAll("\\?$", "");
|
||||
}
|
||||
|
||||
public static String everythingAfterFirstQuestionMark(String input) {
|
||||
return input.substring(input.indexOf('?') + 1);
|
||||
}
|
||||
|
||||
public static boolean hasQuestionMark(StringBuilder sb) {
|
||||
return sb.indexOf("?") != -1;
|
||||
}
|
||||
|
||||
public static void deleteLastCharacter(StringBuilder sb) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
|
||||
public static boolean endsWith(StringBuilder sb, char c) {
|
||||
return sb.length() > 0 && sb.charAt(sb.length() - 1) == c;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.okhttp;
|
||||
|
||||
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class OkHttpRestfulClientFactoryTest {
|
||||
|
||||
private OkHttpRestfulClientFactory clientFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
clientFactory = new OkHttpRestfulClientFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNativeClient_noClientSet_returnsADefault() throws Exception {
|
||||
OkHttpClient actualNativeClient = clientFactory.getNativeClient();
|
||||
|
||||
assertNotNull(actualNativeClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNativeClient_noProxySet_defaultHasNoProxySet() throws Exception {
|
||||
OkHttpClient actualNativeClient = clientFactory.getNativeClient();
|
||||
|
||||
assertEquals(null, actualNativeClient.proxy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHttpClient() {
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder().writeTimeout(5000, TimeUnit.MILLISECONDS).build();
|
||||
|
||||
clientFactory.setHttpClient(okHttpClient);
|
||||
|
||||
assertSame(okHttpClient, clientFactory.getNativeClient());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.okhttp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides server ports
|
||||
*/
|
||||
public class RandomServerPortProvider {
|
||||
|
||||
private static List<Integer> ourPorts = new ArrayList<Integer>();
|
||||
|
||||
public static int findFreePort() {
|
||||
ServerSocket server;
|
||||
try {
|
||||
server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
ourPorts.add(port);
|
||||
server.close();
|
||||
Thread.sleep(500);
|
||||
return port;
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Integer> list() {
|
||||
return ourPorts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package ca.uhn.fhir.okhttp.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class OkHttpRestfulClientTest {
|
||||
|
||||
@Test
|
||||
public void testNewHeaderBuilder_urlHasTrailingSlash_shouldTrim() {
|
||||
StringBuilder headerBuilder = OkHttpRestfulClient.newHeaderBuilder(new StringBuilder("http://localhost/"));
|
||||
|
||||
assertThat(headerBuilder.toString(), equalTo("http://localhost"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewHeaderBuilder_urlHasNoTrailingSlash_shouldNotTrimLastCharacter() {
|
||||
StringBuilder headerBuilder = OkHttpRestfulClient.newHeaderBuilder(new StringBuilder("http://example.com"));
|
||||
|
||||
assertThat(headerBuilder.toString(), equalTo("http://example.com"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<Bundle xmlns="http://hl7.org/fhir">
|
||||
<id value="487d3669-0e1c-4867-b124-400d1849548d"></id>
|
||||
<type value="searchset"></type>
|
||||
<base value="http://localhost:19080/fhir/dstu1"></base>
|
||||
<link>
|
||||
<relation value="just trying add link"></relation>
|
||||
<url value="blarion"></url>
|
||||
</link>
|
||||
<link>
|
||||
<relation value="self"></relation>
|
||||
<url value="http://localhost:19080/fhir/dstu1/Observation?subject.identifier=puppet|CLONE-AA102"></url>
|
||||
</link>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation xmlns="http://hl7.org/fhir">
|
||||
<id value="0d87f02c-da2c-4551-9ead-2956f0165a4f"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="8867-4"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation xmlns="http://hl7.org/fhir">
|
||||
<id value="c54ac0cc-a99f-40aa-9541-c5aa853a2e88"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="3141-9"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
</Bundle>
|
Loading…
Reference in New Issue