diff --git a/hapi-fhir-okhttp/pom.xml b/hapi-fhir-okhttp/pom.xml
new file mode 100644
index 00000000000..c2ff2001c09
--- /dev/null
+++ b/hapi-fhir-okhttp/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+ hapi-fhir
+ ca.uhn.hapi.fhir
+ 2.0-SNAPSHOT
+
+ 4.0.0
+
+ hapi-fhir-okhttp
+ jar
+
+ HAPI FHIR OkHttp Client
+
+
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-base
+ 2.0-SNAPSHOT
+
+
+ commons-logging
+ commons-logging
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.apache.httpcomponents
+ httpcore
+
+
+
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-dstu2
+ 2.0-SNAPSHOT
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-dstu3
+ 2.0-SNAPSHOT
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.4.1
+
+
+
+
+ com.google.guava
+ guava
+ test
+
+
+ org.eclipse.jetty
+ jetty-server
+ test
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ test
+
+
+ org.glassfish.jersey.core
+ jersey-server
+ test
+
+
+ org.glassfish.jersey.containers
+ jersey-container-servlet-core
+ test
+
+
+ org.glassfish.jersey.containers
+ jersey-container-jetty-http
+ test
+
+
+ org.glassfish.jersey.media
+ jersey-media-moxy
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClient.java b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClient.java
new file mode 100644
index 00000000000..0d469f72527
--- /dev/null
+++ b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClient.java
@@ -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> myIfNoneExistParams;
+ private String myIfNoneExistString;
+ private RequestTypeEnum myRequestType;
+ private List myHeaders;
+ private OkHttpRestfulRequest myRequest;
+
+ public OkHttpRestfulClient(OkHttpClient theClient,
+ StringBuilder theUrl,
+ Map> theIfNoneExistParams,
+ String theIfNoneExistString,
+ RequestTypeEnum theRequestType,
+ List 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> theParams, EncodingEnum theEncoding) {
+ initBaseRequest(theContext, theEncoding, getFormBodyFromParams(theParams));
+ return myRequest;
+ }
+
+ private RequestBody getFormBodyFromParams(Map> queryParams) {
+ FormBody.Builder formBuilder = new FormBody.Builder();
+ for (Map.Entry> 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> 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;
+ }
+
+}
diff --git a/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientFactory.java b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientFactory.java
new file mode 100644
index 00000000000..4ed2168c79c
--- /dev/null
+++ b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientFactory.java
@@ -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> theIfNoneExistParams,
+ String theIfNoneExistString,
+ RequestTypeEnum theRequestType,
+ List 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());
+ }
+
+}
diff --git a/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulRequest.java b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulRequest.java
new file mode 100644
index 00000000000..6d3bb20eae7
--- /dev/null
+++ b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulRequest.java
@@ -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> 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();
+ }
+
+}
diff --git a/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulResponse.java b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulResponse.java
new file mode 100644
index 00000000000..aba0e540b6a
--- /dev/null
+++ b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulResponse.java
@@ -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> 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);
+ }
+ }
+ }
+
+}
diff --git a/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/utils/UrlStringUtils.java b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/utils/UrlStringUtils.java
new file mode 100644
index 00000000000..4c96595345a
--- /dev/null
+++ b/hapi-fhir-okhttp/src/main/java/ca/uhn/fhir/okhttp/utils/UrlStringUtils.java
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/GenericOkHttpClientDstu2Test.java b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/GenericOkHttpClientDstu2Test.java
new file mode 100644
index 00000000000..4bae2da6552
--- /dev/null
+++ b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/GenericOkHttpClientDstu2Test.java
@@ -0,0 +1,1955 @@
+package ca.uhn.fhir.okhttp;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.Bundle;
+import ca.uhn.fhir.model.api.Include;
+import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
+import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
+import ca.uhn.fhir.model.dstu2.composite.MetaDt;
+import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
+import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
+import ca.uhn.fhir.model.dstu2.resource.*;
+import ca.uhn.fhir.model.primitive.*;
+import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
+import ca.uhn.fhir.parser.IParser;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.IGenericClient;
+import ca.uhn.fhir.rest.client.RestfulClientFactory;
+import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
+import ca.uhn.fhir.rest.client.api.Header;
+import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
+import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
+import ca.uhn.fhir.rest.method.SearchStyleEnum;
+import ca.uhn.fhir.rest.param.DateRangeParam;
+import ca.uhn.fhir.rest.server.Constants;
+import ca.uhn.fhir.rest.server.EncodingEnum;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.io.Charsets;
+import org.apache.commons.io.IOUtils;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.hl7.fhir.instance.model.api.IBase;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+public class GenericOkHttpClientDstu2Test {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericOkHttpClientDstu2Test.class);
+ private static FhirContext ourCtx;
+ private static int ourPort;
+ private static Server ourServer;
+ private static int ourResponseCount = 0;
+ private static String[] ourResponseBodies;
+ private static String ourResponseBody;
+ private static String ourResponseContentType;
+ private static int ourResponseStatus;
+ private static String ourRequestUri;
+ private static List ourRequestUriAll;
+ private static String ourRequestMethod;
+ private static String ourRequestContentType;
+ private static byte[] ourRequestBodyBytes;
+ private static String ourRequestBodyString;
+ private static ArrayListMultimap ourRequestHeaders;
+ private static List> ourRequestHeadersAll;
+ private static Map ourRequestFirstHeaders;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ ourCtx = FhirContext.forDstu2();
+
+ ourPort = RandomServerPortProvider.findFreePort();
+ ourServer = new Server(ourPort);
+ ourLog.info("Starting server on port {}", ourPort);
+ ourServer.setHandler(new AbstractHandler() {
+
+ @Override
+ public void handle(String theArg0, Request theRequest, HttpServletRequest theServletRequest, HttpServletResponse theResp) throws IOException, ServletException {
+ theRequest.setHandled(true);
+ ourRequestUri = "http:" + theRequest.getHttpURI().toString();
+ ourRequestUriAll.add(ourRequestUri);
+ ourRequestMethod = theRequest.getMethod();
+ ourRequestContentType = theServletRequest.getContentType();
+ ourRequestBodyBytes = IOUtils.toByteArray(theServletRequest.getInputStream());
+ ourRequestBodyString = new String(ourRequestBodyBytes, Charsets.UTF_8);
+
+ ourRequestHeaders = ArrayListMultimap.create();
+ ourRequestHeadersAll.add(ourRequestHeaders);
+ ourRequestFirstHeaders = Maps.newHashMap();
+
+ for (Enumeration headerNameEnum = theRequest.getHeaderNames(); headerNameEnum.hasMoreElements(); ) {
+ String nextName = headerNameEnum.nextElement();
+ for (Enumeration headerValueEnum = theRequest.getHeaders(nextName); headerValueEnum.hasMoreElements(); ) {
+ String nextValue = headerValueEnum.nextElement();
+ if (ourRequestFirstHeaders.containsKey(nextName) == false) {
+ ourRequestFirstHeaders.put(nextName, new Header(nextName, nextValue));
+ }
+ ourRequestHeaders.put(nextName, new Header(nextName, nextValue));
+ }
+ }
+
+ theResp.setStatus(ourResponseStatus);
+
+ if (ourResponseBody != null) {
+ theResp.setContentType(ourResponseContentType);
+ theResp.getWriter().write(ourResponseBody);
+ } else if (ourResponseBodies != null) {
+ theResp.setContentType(ourResponseContentType);
+ theResp.getWriter().write(ourResponseBodies[ourResponseCount]);
+ }
+
+ ourResponseCount++;
+ }
+ });
+
+ ourServer.start();
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ ourServer.stop();
+ }
+
+ /**
+ * This suite of tests can be reconfigured to test a different RestfulClientFactory implementation by
+ * changing the instance returned here.
+ *
+ * @param context FhirContext or null
+ * @return RestfulClientFactory implementation to run tests against
+ */
+ private RestfulClientFactory createNewClientFactoryForTesting(FhirContext context) {
+ if (context == null) {
+ return new OkHttpRestfulClientFactory();
+ } else {
+ return new OkHttpRestfulClientFactory(ourCtx);
+ }
+ }
+
+ @Before
+ public void before() {
+ RestfulClientFactory clientFactory = createNewClientFactoryForTesting(ourCtx);
+ clientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER);
+
+ ourCtx.setRestfulClientFactory(clientFactory);
+ ourResponseCount = 0;
+ }
+
+ @Test
+ public void testProviderWhereWeForgotToSetTheContext() throws Exception {
+ RestfulClientFactory clientFactory = createNewClientFactoryForTesting(null);
+ clientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER);
+
+ ourCtx.setRestfulClientFactory(clientFactory);
+
+ try {
+ ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+ fail();
+ } catch (IllegalStateException e) {
+ String factoryClassName = clientFactory.getClass().getSimpleName();
+ assertEquals(factoryClassName + " does not have FhirContext defined. This must be set via " + factoryClassName + "#setFhirContext(FhirContext)", e.getMessage());
+ }
+ }
+
+ private String getPatientFeedWithOneResult() {
+ //@formatter:off
+ String msg = "\n" +
+ "d039f91a-cc3c-4013-988e-af4d8d0614bd\n" +
+ "\n" +
+ ""
+ + ""
+ + "John Cardinal: 444333333
"
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + "\n"
+ + " \n"
+ + "";
+ //@formatter:on
+ return msg;
+ }
+
+ @Test
+ public void testAcceptHeaderFetchConformance() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final String respString = p.encodeResourceToString(conf);
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ client.fetchConformance().ofType(Conformance.class).execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUri);
+ assertEquals(1, ourRequestHeaders.get("Accept").size());
+ assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY));
+
+ client.fetchConformance().ofType(Conformance.class).encodedJson().execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=json", ourRequestUri);
+ assertEquals(1, ourRequestHeaders.get("Accept").size());
+ assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON));
+
+ client.fetchConformance().ofType(Conformance.class).encodedXml().execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=xml", ourRequestUri);
+ assertEquals(1, ourRequestHeaders.get("Accept").size());
+ assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML));
+ }
+
+ @Test
+ public void testAcceptHeaderPreflightConformance() throws Exception {
+ final IParser p = ourCtx.newXmlParser();
+
+ final Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY");
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBodies = new String[]{p.encodeResourceToString(conf), p.encodeResourceToString(patient)};
+
+ ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient resp = client.read(Patient.class, new IdDt("123"));
+ assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUriAll.get(0));
+ assertEquals(1, ourRequestHeadersAll.get(0).get("Accept").size());
+ assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY));
+ assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML));
+ assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUriAll.get(1));
+ assertEquals(1, ourRequestHeadersAll.get(1).get("Accept").size());
+ assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY));
+ assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML));
+ assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON));
+ }
+
+ @Test
+ public void testAcceptHeaderPreflightConformancePreferJson() throws Exception {
+ final IParser p = ourCtx.newXmlParser();
+
+ final Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final Patient patient = new Patient();
+ patient.addName().addFamily("FAMILY");
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBodies = new String[]{p.encodeResourceToString(conf), p.encodeResourceToString(patient)};
+
+ ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+ client.setEncoding(EncodingEnum.JSON);
+
+ Patient resp = client.read(Patient.class, new IdDt("123"));
+ assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=json", ourRequestUriAll.get(0));
+ assertEquals(1, ourRequestHeadersAll.get(0).get("Accept").size());
+ assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON));
+ assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), not(containsString(Constants.CT_FHIR_XML)));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=json", ourRequestUriAll.get(1));
+ assertEquals(1, ourRequestHeadersAll.get(1).get("Accept").size());
+ assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON));
+ assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), not(containsString(Constants.CT_FHIR_XML)));
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void testConformance() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final String respString = p.encodeResourceToString(conf);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Conformance resp = (Conformance) client.conformance();
+
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUri);
+ assertEquals("COPY", resp.getCopyright());
+ assertEquals("GET", ourRequestMethod);
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.create().resource(p).execute();
+
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+
+ p.setId("123");
+
+ client.create().resource(p).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ String body = ourRequestBodyString;
+ assertThat(body, containsString(""));
+ assertThat(body, not(containsString("123")));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ }
+
+ @Test
+ public void testCreateConditional() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ String expectedContentTypeHeader = EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8;
+ assertContentTypeEquals(expectedContentTypeHeader);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue());
+ assertEquals("POST", ourRequestMethod);
+
+ client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(expectedContentTypeHeader);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue());
+ assertEquals("POST", ourRequestMethod);
+
+ client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(expectedContentTypeHeader);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue());
+ assertEquals("POST", ourRequestMethod);
+ }
+
+ private void assertContentTypeEquals(String expectedContentTypeHeader) {
+ // charsets are case-insensitive according to the HTTP spec (e.g. utf-8 == UTF-8):
+ // https://tools.ietf.org/html/rfc2616#section-3.4
+ assertThat(getActualContentTypeHeader(), equalToIgnoringCase(expectedContentTypeHeader));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void testCreateNonFluent() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.create(p);
+
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ }
+
+ @Test
+ public void testCreatePrefer() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.create().resource(p).prefer(PreferReturnEnum.MINIMAL).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size());
+ assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_MINIMAL, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue());
+
+ client.create().resource(p).prefer(PreferReturnEnum.REPRESENTATION).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size());
+ assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_REPRESENTATION, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue());
+ }
+
+ @Test
+ public void testCreateReturningResourceBody() throws Exception {
+ Patient p = new Patient();
+ p.setId("123");
+ final String formatted = ourCtx.newXmlParser().encodeResourceToString(p);
+
+ ourResponseStatus = Constants.STATUS_HTTP_200_OK;
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = formatted;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ p = new Patient();
+ p.setId(new IdDt("1"));
+ p.addName().addFamily("FOOFAMILY");
+
+ MethodOutcome output = client.create().resource(p).execute();
+ assertNotNull(output.getResource());
+ assertEquals("Patient/123", output.getResource().getIdElement().toUnqualifiedVersionless().getValue());
+ }
+
+ @Test
+ public void testDeleteConditional() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ client.delete().resourceById(new IdDt("Patient/123")).execute();
+ assertEquals("DELETE", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+
+ client.delete().resourceConditionalByUrl("Patient?name=foo").execute();
+ assertEquals("DELETE", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
+
+ client.delete().resourceConditionalByType("Patient").where(Patient.NAME.matches().value("foo")).execute();
+ assertEquals("DELETE", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void testDeleteNonFluent() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ client.delete(Patient.class, new IdDt("Patient/123"));
+ assertEquals("DELETE", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+
+ client.delete(Patient.class, "123");
+ assertEquals("DELETE", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+ }
+
+ @Test
+ public void testHistory() throws Exception {
+ final String msg = getPatientFeedWithOneResult();
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle response;
+
+ //@formatter:off
+ response = client
+ .history()
+ .onServer()
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri);
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onServer()
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .since((Date) null)
+ .count(null)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri);
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onServer()
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .since(new InstantDt())
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri);
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onType(Patient.class)
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/_history", ourRequestUri);
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onInstance(new IdDt("Patient", "123"))
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/_history", ourRequestUri);
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onInstance(new IdDt("Patient", "123"))
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .count(123)
+ .since(new InstantDt("2001-01-02T11:22:33Z"))
+ .execute();
+ //@formatter:on
+ assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123/_history?_since=2001-01-02T11:22:33Z&_count=123")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123/_history?_count=123&_since=2001-01-02T11:22:33Z")));
+ assertEquals(1, response.getEntry().size());
+
+ //@formatter:off
+ response = client
+ .history()
+ .onInstance(new IdDt("Patient", "123"))
+ .andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .since(new InstantDt("2001-01-02T11:22:33Z").getValue())
+ .execute();
+ //@formatter:on
+ assertThat(ourRequestUri, containsString("_since=2001-01"));
+ assertEquals(1, response.getEntry().size());
+ }
+
+ @Test
+ public void testMetaAdd() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ MetaDt inMeta = new MetaDt().addProfile("urn:profile:in");
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ MetaDt resp = client
+ .meta()
+ .add()
+ .onResource(new IdDt("Patient/123"))
+ .meta(inMeta)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta-add", ourRequestUri);
+ assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("", ourRequestBodyString);
+ }
+
+ @Test
+ public void testMetaGet() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:in"));
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ MetaDt resp = client
+ .meta()
+ .get(MetaDt.class)
+ .fromServer()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$meta", ourRequestUri);
+ assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .meta()
+ .get(MetaDt.class)
+ .fromType("Patient")
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$meta", ourRequestUri);
+ assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .meta()
+ .get(MetaDt.class)
+ .fromResource(new IdDt("Patient/123"))
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta", ourRequestUri);
+ assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
+ assertEquals("GET", ourRequestMethod);
+ }
+
+ @Test
+ public void testOperationAsGetWithInParameters() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setName("param1").setValue(new StringDt("STRINGVALIN1"));
+ inParams.addParameter().setName("param1").setValue(new StringDt("STRINGVALIN1b"));
+ inParams.addParameter().setName("param2").setValue(new StringDt("STRINGVALIN2"));
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameters(inParams)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onType(Patient.class)
+ .named("$SOMEOPERATION")
+ .withParameters(inParams)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("Patient", "123"))
+ .named("$SOMEOPERATION")
+ .withParameters(inParams)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ // @formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("http://foo.com/bar/baz/Patient/123/_history/22"))
+ .named("$SOMEOPERATION")
+ .withParameters(inParams)
+ .useHttpGet()
+ .execute();
+ // @formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri);
+ }
+
+ @Test
+ public void testOperationAsGetWithNoInParameters() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onType(Patient.class)
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("Patient", "123"))
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class)
+ .useHttpGet()
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals("GET", ourRequestMethod);
+
+ // @formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("http://foo.com/bar/baz/Patient/123/_history/22"))
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class)
+ .useHttpGet()
+ .execute();
+ // @formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ }
+
+ @Test
+ public void testOperationWithBundleResponseJson() throws Exception {
+ ourResponseContentType = Constants.CT_FHIR_JSON;
+ final String respString = "{\n" + " \"resourceType\":\"Bundle\",\n" + " \"id\":\"8cef5f2a-0ba9-43a5-be26-c8dde9ff0e19\",\n" + " \"base\":\"http://localhost:" + ourPort + "/fhir\"\n" + "}";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ client.registerInterceptor(new LoggingInterceptor(true));
+
+ // Create the input parameters to pass to the server
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
+ inParams.addParameter().setName("end").setValue(new DateDt("2015-03-01"));
+
+ // Invoke $everything on "Patient/1"
+ Parameters outParams = client.operation().onInstance(new IdDt("Patient", "18066")).named("$everything").withParameters(inParams).execute();
+
+ /*
+ * Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation
+ * methods return a Parameters instance however, so HAPI creates a Parameters object
+ * with a single parameter containing the value.
+ */
+ ca.uhn.fhir.model.dstu2.resource.Bundle responseBundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) outParams.getParameter().get(0).getResource();
+
+ // Print the response bundle
+ assertEquals("8cef5f2a-0ba9-43a5-be26-c8dde9ff0e19", responseBundle.getId().getIdPart());
+ }
+
+ @Test
+ public void testOperationWithBundleResponseXml() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setValue(new StringDt("STRINGVALIN1"));
+ inParams.addParameter().setValue(new StringDt("STRINGVALIN2"));
+ String reqString = p.encodeResourceToString(inParams);
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle outParams = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ outParams.setTotal(123);
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameters(inParams).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals(1, resp.getParameter().size());
+ assertEquals(ca.uhn.fhir.model.dstu2.resource.Bundle.class, resp.getParameter().get(0).getResource().getClass());
+ }
+
+ @Test
+ public void testOperationWithInlineParams() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameter(Parameters.class, "name1", new StringDt("value1"))
+ .andParameter("name2", new StringDt("value1"))
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("", (ourRequestBodyString));
+
+ /*
+ * Composite type
+ */
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
+ .andParameter("name2", new StringDt("value1"))
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("",
+ (ourRequestBodyString));
+
+ /*
+ * Resource
+ */
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
+ .andParameter("name2", new Patient().setActive(true))
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals(
+ "",
+ (ourRequestBodyString));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testOperationWithInvalidParam() {
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ // Who knows what the heck this is!
+ IBase weirdBase = new IBase() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean hasFormatComment() {
+ return false;
+ }
+
+ @Override
+ public List getFormatCommentsPre() {
+ return null;
+ }
+
+ @Override
+ public List getFormatCommentsPost() {
+ return null;
+ }
+ };
+
+ //@formatter:off
+ client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameter(Parameters.class, "name1", weirdBase)
+ .execute();
+ //@formatter:on
+ }
+
+ @Test
+ public void testOperationWithProfiledDatatypeParam() throws IOException, Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ client
+ .operation()
+ .onInstance(new IdDt("http://foo/Patient/1"))
+ .named("validate-code")
+ .withParameter(Parameters.class, "code", new CodeDt("8495-4"))
+ .andParameter("system", new UriDt("http://loinc.org"))
+ .useHttpGet()
+ .execute();
+ //@formatter:off
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/1/$validate-code?code=8495-4&system=http%3A%2F%2Floinc.org", ourRequestUri);
+
+ //@formatter:off
+
+ client
+ .operation()
+ .onInstance(new IdDt("http://foo/Patient/1"))
+ .named("validate-code")
+ .withParameter(Parameters.class, "code", new CodeDt("8495-4"))
+ .andParameter("system", new UriDt("http://loinc.org"))
+ .execute();
+ //@formatter:off
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/1/$validate-code", ourRequestUri);
+ ourLog.info(ourRequestBodyString);
+ assertEquals("", ourRequestBodyString);
+ }
+
+ @Test
+ public void testOperationWithListOfParameterResponse() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setValue(new StringDt("STRINGVALIN1"));
+ inParams.addParameter().setValue(new StringDt("STRINGVALIN2"));
+ String reqString = p.encodeResourceToString(inParams);
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withParameters(inParams).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onType(Patient.class)
+ .named("$SOMEOPERATION")
+ .withParameters(inParams).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("Patient", "123"))
+ .named("$SOMEOPERATION")
+ .withParameters(inParams).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ resp = client.operation().onInstance(new IdDt("http://foo.com/bar/baz/Patient/123/_history/22")).named("$SOMEOPERATION").withParameters(inParams).execute();
+ // @formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ }
+
+ @Test
+ public void testOperationWithNoInParameters() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Parameters inParams = new Parameters();
+ final String reqString = p.encodeResourceToString(inParams);
+
+ Parameters outParams = new Parameters();
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT1"));
+ outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
+ final String respString = p.encodeResourceToString(outParams);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Parameters resp = client
+ .operation()
+ .onServer()
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onType(Patient.class)
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ //@formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("Patient", "123"))
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class).execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ assertEquals(respString, p.encodeResourceToString(resp));
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertEquals(ourRequestBodyString, reqString);
+ assertEquals("POST", ourRequestMethod);
+
+ // @formatter:off
+ resp = client
+ .operation()
+ .onInstance(new IdDt("http://foo.com/bar/baz/Patient/123/_history/22"))
+ .named("$SOMEOPERATION")
+ .withNoParameters(Parameters.class)
+ .execute();
+ // @formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
+ }
+
+ @Test
+ public void testPageNext() throws Exception {
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = getPatientFeedWithOneResult();
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle sourceBundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ sourceBundle.getLinkOrCreate(IBaseBundle.LINK_PREV).setUrl("http://localhost:" + ourPort + "/fhir/prev");
+ sourceBundle.getLinkOrCreate(IBaseBundle.LINK_NEXT).setUrl("http://localhost:" + ourPort + "/fhir/next");
+
+ //@formatter:off
+ ca.uhn.fhir.model.dstu2.resource.Bundle resp = client
+ .loadPage()
+ .next(sourceBundle)
+ .execute();
+ //@formatter:on
+
+ assertEquals(1, resp.getEntry().size());
+ assertEquals("http://localhost:" + ourPort + "/fhir/next", ourRequestUri);
+ }
+
+ @Test
+ public void testPageNextNoLink() throws Exception {
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle sourceBundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ try {
+ client.loadPage().next(sourceBundle).execute();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("Can not perform paging operation because no link was found in Bundle with relation \"next\""));
+ }
+ }
+
+ @Test
+ public void testPagePrev() throws Exception {
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = getPatientFeedWithOneResult();
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle sourceBundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ sourceBundle.getLinkOrCreate("previous").setUrl("http://localhost:" + ourPort + "/fhir/prev");
+
+ //@formatter:off
+ ca.uhn.fhir.model.dstu2.resource.Bundle resp = client
+ .loadPage()
+ .previous(sourceBundle)
+ .execute();
+ //@formatter:on
+
+ assertEquals(1, resp.getEntry().size());
+ assertEquals("http://localhost:" + ourPort + "/fhir/prev", ourRequestUri);
+
+
+ /*
+ * Try with "prev" instead of "previous"
+ */
+
+ sourceBundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ sourceBundle.getLinkOrCreate("prev").setUrl("http://localhost:" + ourPort + "/fhir/prev");
+
+ //@formatter:off
+ resp = client
+ .loadPage()
+ .previous(sourceBundle)
+ .execute();
+ //@formatter:on
+
+ assertEquals(1, resp.getEntry().size());
+ assertEquals("http://localhost:" + ourPort + "/fhir/prev", ourRequestUri);
+ }
+
+ @Test
+ public void testReadByUri() throws Exception {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAM");
+ final String respString = ourCtx.newXmlParser().encodeResourceToString(patient);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient response;
+
+ response = (Patient) client.read(new UriDt("http://localhost:" + ourPort + "/fhir/Patient/123"));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+ assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue());
+ }
+
+ @Test
+ public void testReadFluentByUri() throws Exception {
+ Patient patient = new Patient();
+ patient.addName().addFamily("FAM");
+ final String respString = ourCtx.newXmlParser().encodeResourceToString(patient);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient response;
+
+ response = (Patient) client.read().resource(Patient.class).withUrl(new IdDt("http://localhost:" + ourPort + "/AAA/Patient/123")).execute();
+ assertEquals("http://localhost:" + ourPort + "/AAA/Patient/123", ourRequestUri);
+ assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue());
+ }
+
+ @Test
+ public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception {
+ //@formatter:off
+ final String input = "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+ //@formatter:on
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = input;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle response;
+
+ //@formatter:off
+ response = client
+ .search()
+ .forResource(Patient.class)
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+
+ assertEquals("2015-06-22T15:48:57.554-04:00", ResourceMetadataKeyEnum.UPDATED.get(response).getValueAsString());
+ }
+
+ @Test
+ public void testReadWithElementsParam() throws Exception {
+ String msg = "{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ IBaseResource response = client.read()
+ .resource("Patient")
+ .withId("123")
+ .elementsSubset("name", "identifier")
+ .execute();
+ //@formatter:on
+
+ assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123?_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123?_elements=identifier%2Cname")));
+ assertEquals(Patient.class, response.getClass());
+ }
+
+ @Test
+ public void testReadWithSummaryInvalid() throws Exception {
+ String msg = "<>>>><<<<>";
+
+ ourResponseContentType = Constants.CT_HTML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ try {
+ client.read()
+ .resource(Patient.class)
+ .withId("123")
+ .summaryMode(SummaryEnum.TEXT)
+ .execute();
+ fail();
+ } catch (InvalidResponseException e) {
+ assertThat(e.getMessage(), containsString("String does not appear to be valid"));
+ }
+ //@formatter:on
+ }
+
+ @Test
+ public void testReadWithSummaryParamHtml() throws Exception {
+ String msg = "HELP IM A DIV
";
+
+ ourResponseContentType = Constants.CT_HTML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Patient response = client.read()
+ .resource(Patient.class)
+ .withId("123")
+ .summaryMode(SummaryEnum.TEXT)
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_summary=text", ourRequestUri);
+ assertEquals(Patient.class, response.getClass());
+ assertEquals("HELP IM A DIV
", response.getText().getDiv().getValueAsString());
+ }
+
+ @Test
+ public void testSearchByString() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james", ourRequestUri);
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+ }
+
+ @Test
+ public void testSearchByUrl() throws Exception {
+ final String msg = getPatientFeedWithOneResult();
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ ca.uhn.fhir.model.dstu2.resource.Bundle response = client.search()
+ .byUrl("http://localhost:" + ourPort + "/AAA?name=http://foo|bar")
+ .encodedJson()
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/AAA?name=http%3A//foo%7Cbar&_format=json", ourRequestUri);
+ assertNotNull(response);
+
+ //@formatter:off
+ response = client.search()
+ .byUrl("Patient?name=http://foo|bar")
+ .encodedJson()
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar&_format=json", ourRequestUri);
+ assertNotNull(response);
+
+ //@formatter:off
+ response = client.search()
+ .byUrl("/Patient?name=http://foo|bar")
+ .encodedJson()
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar&_format=json", ourRequestUri);
+ assertNotNull(response);
+
+ //@formatter:off
+ response = client.search()
+ .byUrl("Patient")
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertNotNull(response);
+
+ //@formatter:off
+ response = client.search()
+ .byUrl("Patient?")
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri);
+ assertNotNull(response);
+
+ try {
+ client.search().byUrl("foo/bar?test=1");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Search URL must be either a complete URL starting with http: or https:, or a relative FHIR URL in the form [ResourceType]?[Params]", e.getMessage());
+ }
+ }
+
+ /**
+ * See #191
+ */
+ @Test
+ public void testSearchReturningDstu2Bundle() throws Exception {
+ String msg = IOUtils.toString(GenericOkHttpClientDstu2Test.class.getResourceAsStream("/bundle_orion.xml"));
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ ca.uhn.fhir.model.dstu2.resource.Bundle response = client.search()
+ .forResource("Observation")
+ .where(Patient.NAME.matches().value("FOO"))
+ .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
+ .execute();
+ //@formatter:on
+
+ Link link = response.getLink().get(0);
+ assertEquals("just trying add link", link.getRelation());
+ assertEquals("blarion", link.getUrl());
+
+ Entry entry = response.getEntry().get(0);
+ link = entry.getLink().get(0);
+ assertEquals("orionhealth.edit", link.getRelation());
+ assertEquals("Observation", link.getUrl());
+ }
+
+ @Test
+ public void testSearchWithElementsParam() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .elementsSubset("name", "identifier")
+ .execute();
+ //@formatter:on
+
+ assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname")));
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+ }
+
+ @Test
+ public void testSearchByPost() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .elementsSubset("name", "identifier")
+ .usingStyle(SearchStyleEnum.POST)
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/_search?_elements=identifier%2Cname", ourRequestUri);
+
+ // assertThat(ourRequestUri,
+ // either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname")));
+
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+
+ assertEquals("name=james", ourRequestBodyString);
+
+ assertEquals("application/x-www-form-urlencoded", ourRequestContentType.replace(";char", "; char").toLowerCase());
+ assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY, ourRequestFirstHeaders.get("Accept").getValue());
+ assertThat(ourRequestFirstHeaders.get("User-Agent").getValue(), not(emptyString()));
+ }
+
+ @Test
+ public void testSearchByPostUseJson() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .elementsSubset("name", "identifier")
+ .usingStyle(SearchStyleEnum.POST)
+ .encodedJson()
+ .execute();
+ //@formatter:on
+
+ assertThat(ourRequestUri, containsString("http://localhost:" + ourPort + "/fhir/Patient/_search?"));
+ assertThat(ourRequestUri, containsString("_elements=identifier%2Cname"));
+ assertThat(ourRequestUri, not(containsString("_format=json")));
+
+ // assertThat(ourRequestUri,
+ // either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname")));
+
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+
+ assertEquals("name=james", ourRequestBodyString);
+
+ assertEquals("application/x-www-form-urlencoded", ourRequestContentType);
+ assertEquals(Constants.CT_FHIR_JSON, ourRequestFirstHeaders.get("Accept").getValue());
+ }
+
+ @Test
+ public void testSearchWithLastUpdated() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .lastUpdated(new DateRangeParam("2011-01-01", "2012-01-01"))
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james&_lastUpdated=ge2011-01-01&_lastUpdated=le2012-01-01", ourRequestUri);
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+ }
+
+ @Test
+ public void testSearchWithProfileAndSecurity() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .withProfile("http://foo1")
+ .withProfile("http://foo2")
+ .withSecurity("system1", "code1")
+ .withSecurity("system2", "code2")
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?_security=system1%7Ccode1&_security=system2%7Ccode2&_profile=http%3A%2F%2Ffoo1&_profile=http%3A%2F%2Ffoo2", ourRequestUri);
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+ }
+
+ @SuppressWarnings("unused")
+ @Test
+ public void testSearchWithReverseInclude() throws Exception {
+ String msg = getPatientFeedWithOneResult();
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource(Patient.class)
+ .encodedJson()
+ .revInclude(new Include("Provenance:target"))
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?_revinclude=Provenance%3Atarget&_format=json", ourRequestUri);
+ }
+
+ @Test
+ public void testSearchWithSummaryParam() throws Exception {
+ String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ Bundle response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("james"))
+ .summaryMode(SummaryEnum.FALSE)
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james&_summary=false", ourRequestUri);
+ assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
+ }
+
+ @Test
+ public void testTransactionWithListOfResources() throws Exception {
+ ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
+ resp.addEntry().getResponse().setLocation("Patient/2/_history/2");
+ String respString = ourCtx.newJsonParser().encodeResourceToString(resp);
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ List input = new ArrayList();
+
+ Patient p1 = new Patient(); // No ID
+ p1.addName().addFamily("PATIENT1");
+ input.add(p1);
+
+ Patient p2 = new Patient(); // Yes ID
+ p2.addName().addFamily("PATIENT2");
+ p2.setId("Patient/2");
+ input.add(p2);
+
+ //@formatter:off
+ List response = client.transaction()
+ .withResources(input)
+ .encodedJson()
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir", ourRequestUri);
+ assertEquals(2, response.size());
+
+ String requestString = ourRequestBodyString;
+ ca.uhn.fhir.model.dstu2.resource.Bundle requestBundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, requestString);
+ assertEquals(2, requestBundle.getEntry().size());
+ assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
+ assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
+ assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
+
+ p1 = (Patient) response.get(0);
+ assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
+ // assertEquals("PATIENT1", p1.getName().get(0).getFamily().get(0).getValue());
+
+ p2 = (Patient) response.get(1);
+ assertEquals(new IdDt("Patient/2/_history/2"), p2.getId().toUnqualified());
+ // assertEquals("PATIENT2", p2.getName().get(0).getFamily().get(0).getValue());
+ }
+
+ @Test
+ public void testTransactionWithString() throws Exception {
+ ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ Patient patient = new Patient();
+ patient.addName().addFamily("PAT_FAMILY");
+ req.addEntry().setResource(patient);
+ Observation observation = new Observation();
+ observation.getCode().setText("OBS_TEXT");
+ req.addEntry().setResource(observation);
+ String reqString = ourCtx.newJsonParser().encodeResourceToString(req);
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
+ resp.addEntry().getResponse().setLocation("Patient/2/_history/2");
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = reqString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ //@formatter:off
+ String response = client.transaction()
+ .withBundle(reqString)
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/", ourRequestUri);
+ assertThat(response, containsString("\"Bundle\""));
+ assertContentTypeEquals("application/json+fhir; charset=UTF-8");
+
+ //@formatter:off
+ response = client.transaction()
+ .withBundle(reqString)
+ .encodedXml()
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/", ourRequestUri);
+ assertContentTypeEquals("application/xml+fhir; charset=UTF-8");
+ }
+
+ @Test
+ public void testTransactionWithTransactionResource() throws Exception {
+ ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+ resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
+ resp.addEntry().getResponse().setLocation("Patient/2/_history/2");
+ String respString = ourCtx.newJsonParser().encodeResourceToString(resp);
+
+ ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
+ ourResponseBody = respString;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ ca.uhn.fhir.model.dstu2.resource.Bundle input = new ca.uhn.fhir.model.dstu2.resource.Bundle();
+
+ Patient p1 = new Patient(); // No ID
+ p1.addName().addFamily("PATIENT1");
+ input.addEntry().setResource(p1);
+
+ Patient p2 = new Patient(); // Yes ID
+ p2.addName().addFamily("PATIENT2");
+ p2.setId("Patient/2");
+ input.addEntry().setResource(p2);
+
+ //@formatter:off
+ ca.uhn.fhir.model.dstu2.resource.Bundle response = client.transaction()
+ .withBundle(input)
+ .encodedJson()
+ .execute();
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir", ourRequestUri);
+ assertEquals(2, response.getEntry().size());
+
+ assertEquals("Patient/1/_history/1", response.getEntry().get(0).getResponse().getLocation());
+ assertEquals("Patient/2/_history/2", response.getEntry().get(1).getResponse().getLocation());
+ }
+
+ @Test
+ public void testUpdateConditional() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("PUT", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
+
+ client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("PUT", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar", ourRequestUri);
+
+ client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("PUT", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
+
+ client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("PUT", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo&address=AAA%5C%7CBBB", ourRequestUri);
+
+ client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("PUT", ourRequestMethod);
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo&address=AAA%5C%7CBBB", ourRequestUri);
+ }
+
+ private String getActualContentTypeHeader() {
+ return ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char");
+ }
+
+ @Test
+ public void testUpdateNonFluent() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addFamily("FOOFAMILY");
+
+ client.update(new IdDt("Patient/123"), p);
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+
+ String expectedContentTypeHeader = EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8;
+ assertThat(getActualContentTypeHeader(), equalToIgnoringCase(expectedContentTypeHeader));
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+ assertEquals("PUT", ourRequestMethod);
+
+ client.update("123", p);
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
+ assertThat(getActualContentTypeHeader(), equalToIgnoringCase(expectedContentTypeHeader));
+ assertThat(ourRequestBodyString, containsString(""));
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
+ assertEquals("PUT", ourRequestMethod);
+ }
+
+ @Test
+ public void testUpdatePrefer() throws Exception {
+ ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.setId(new IdDt("1"));
+ p.addName().addFamily("FOOFAMILY");
+
+ client.update().resource(p).prefer(PreferReturnEnum.MINIMAL).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size());
+ assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_MINIMAL, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue());
+
+ client.update().resource(p).prefer(PreferReturnEnum.REPRESENTATION).execute();
+ assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size());
+ assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_REPRESENTATION, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue());
+ }
+
+ @Test
+ public void testUpdateReturningResourceBody() throws Exception {
+ Patient p = new Patient();
+ p.setId("123");
+ final String formatted = ourCtx.newXmlParser().encodeResourceToString(p);
+
+ ourResponseStatus = Constants.STATUS_HTTP_200_OK;
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = formatted;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ p = new Patient();
+ p.setId(new IdDt("1"));
+ p.addName().addFamily("FOOFAMILY");
+
+ MethodOutcome output = client.update().resource(p).execute();
+ assertNotNull(output.getResource());
+ assertEquals("Patient/123", output.getResource().getIdElement().toUnqualifiedVersionless().getValue());
+ }
+
+ @Test
+ public void testValidateFluent() throws Exception {
+ OperationOutcome oo = new OperationOutcome();
+ oo.addIssue().setDiagnostics("FOOBAR");
+ final String msg = ourCtx.newXmlParser().encodeResourceToString(oo);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addGiven("GIVEN");
+
+ MethodOutcome response;
+
+ response = client.validate().resource(p).execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("", ourRequestBodyString);
+ assertNotNull(response.getOperationOutcome());
+ assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
+
+ response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("", ourRequestBodyString);
+ assertNotNull(response.getOperationOutcome());
+ assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
+
+ response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"given\":[\"GIVEN\"]}]}}]}", ourRequestBodyString);
+ assertNotNull(response.getOperationOutcome());
+ assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
+
+ response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).prettyPrint().execute();
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_pretty=true", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ assertThat(ourRequestBodyString, containsString("\"resourceType\": \"Parameters\",\n"));
+ assertNotNull(response.getOperationOutcome());
+ assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
+ }
+
+ @Test
+ public void testValidateNonFluent() throws Exception {
+ OperationOutcome oo = new OperationOutcome();
+ oo.addIssue().setDiagnostics("FOOBAR");
+ final String msg = ourCtx.newXmlParser().encodeResourceToString(oo);
+
+ ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
+ ourResponseBody = msg;
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
+
+ Patient p = new Patient();
+ p.addName().addGiven("GIVEN");
+
+ MethodOutcome response;
+
+ //@formatter:off
+ response = client.validate(p);
+ //@formatter:on
+
+ assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
+ assertEquals("POST", ourRequestMethod);
+ assertEquals("", ourRequestBodyString);
+ assertNotNull(response.getOperationOutcome());
+ assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
+ }
+
+ private OperationOutcome toOo(IBaseOperationOutcome theOperationOutcome) {
+ return (OperationOutcome) theOperationOutcome;
+ }
+
+ @Before
+ public void beforeReset() {
+ ourRequestUri = null;
+ ourRequestUriAll = Lists.newArrayList();
+ ourResponseStatus = 200;
+ ourResponseBody = null;
+ ourResponseBodies = null;
+ ourResponseCount = 0;
+
+ ourResponseContentType = null;
+ ourRequestContentType = null;
+ ourRequestBodyBytes = null;
+ ourRequestBodyString = null;
+ ourRequestHeaders = null;
+ ourRequestFirstHeaders = null;
+ ourRequestMethod = null;
+ ourRequestHeadersAll = Lists.newArrayList();
+ }
+}
diff --git a/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/OkHttpRestfulClientFactoryTest.java b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/OkHttpRestfulClientFactoryTest.java
new file mode 100644
index 00000000000..fab3ada4d98
--- /dev/null
+++ b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/OkHttpRestfulClientFactoryTest.java
@@ -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());
+ }
+
+}
\ No newline at end of file
diff --git a/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/RandomServerPortProvider.java b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/RandomServerPortProvider.java
new file mode 100644
index 00000000000..f079d1ee396
--- /dev/null
+++ b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/RandomServerPortProvider.java
@@ -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 ourPorts = new ArrayList();
+
+ 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 list() {
+ return ourPorts;
+ }
+
+}
+
\ No newline at end of file
diff --git a/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientTest.java b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientTest.java
new file mode 100644
index 00000000000..ff147f57e3b
--- /dev/null
+++ b/hapi-fhir-okhttp/src/test/java/ca/uhn/fhir/okhttp/client/OkHttpRestfulClientTest.java
@@ -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"));
+ }
+
+}
\ No newline at end of file
diff --git a/hapi-fhir-okhttp/src/test/resources/bundle_orion.xml b/hapi-fhir-okhttp/src/test/resources/bundle_orion.xml
new file mode 100644
index 00000000000..7f2fc0a8275
--- /dev/null
+++ b/hapi-fhir-okhttp/src/test/resources/bundle_orion.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8578e27f223..31a4d406523 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1576,5 +1576,6 @@
+ hapi-fhir-okhttp