Switch default client to JSON (#1392)

* Start work on changing over

* Update tests

* More test fixes

* Work on generalizing binary access provider a bit

* Add expunge capability to binary storage, and also support actual binary
resources

* Work on binary provider

* Get the DB bound binary storage service working

* Test fixes

* Compile fix

* Fix compile error

* Test fix

* Test tweak

* Trying to figure out an intermittent failure

* Work on tests

* More work on tests

* Another test fix
This commit is contained in:
James Agnew 2019-07-22 21:27:10 -04:00 committed by GitHub
parent 03918fe29a
commit 7e3d062d15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 1749 additions and 530 deletions

View File

@ -1163,6 +1163,42 @@ public enum Pointcut {
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
),
/**
* Invoked before a resource is about to be expunged via the <code>$expunge</code> operation.
* <p>
* Hooks may accept the following parameters:
* </p>
* <ul>
* <li>org.hl7.fhir.instance.model.api.IIdType - The ID of the resource that is about to be deleted</li>
* <li>org.hl7.fhir.instance.model.api.IBaseResource - The resource that is about to be deleted</li>
* <li>
* ca.uhn.fhir.rest.api.server.RequestDetails - A bean containing details about the request that is about to be processed, including details such as the
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
* pulled out of the servlet request. Note that the bean
* properties are not all guaranteed to be populated, depending on how early during processing the
* exception occurred.
* </li>
* <li>
* ca.uhn.fhir.rest.server.servlet.ServletRequestDetails - A bean containing details about the request that is about to be processed, including details such as the
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* </ul>
* <p>
* Hooks should return void.
* </p>
*/
STORAGE_PRESTORAGE_EXPUNGE_RESOURCE(
// Return type
void.class,
// Params
"org.hl7.fhir.instance.model.api.IIdType",
"org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
),
/**
* Invoked before expungeEverything is called.
* <p>
@ -1190,7 +1226,6 @@ public enum Pointcut {
* Hooks should return void.
* </p>
*/
STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING(
// Return type
void.class,

View File

@ -80,7 +80,7 @@ public abstract class BaseParser implements IParser {
}
@Override
public void setDontEncodeElements(Set<String> theDontEncodeElements) {
public IParser setDontEncodeElements(Set<String> theDontEncodeElements) {
if (theDontEncodeElements == null || theDontEncodeElements.isEmpty()) {
myDontEncodeElements = null;
} else {
@ -89,6 +89,7 @@ public abstract class BaseParser implements IParser {
.map(ElementsPath::new)
.collect(Collectors.toList());
}
return this;
}
List<ElementsPath> getEncodeElements() {
@ -96,7 +97,7 @@ public abstract class BaseParser implements IParser {
}
@Override
public void setEncodeElements(Set<String> theEncodeElements) {
public IParser setEncodeElements(Set<String> theEncodeElements) {
if (theEncodeElements == null || theEncodeElements.isEmpty()) {
myEncodeElements = null;
@ -122,6 +123,8 @@ public abstract class BaseParser implements IParser {
}
}
return this;
}
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
@ -1112,7 +1115,9 @@ public abstract class BaseParser implements IParser {
private boolean checkIfPathMatchesForEncoding(List<ElementsPath> theElements, boolean theCheckingForEncodeElements) {
boolean retVal = false;
myEncodeContext.pushPath(myDef.getElementName(), false);
if (myDef != null) {
myEncodeContext.pushPath(myDef.getElementName(), false);
}
if (theCheckingForEncodeElements && isEncodeElementsAppliesToChildResourcesOnly() && myEncodeContext.getResourcePath().size() < 2) {
retVal = true;
@ -1144,7 +1149,10 @@ public abstract class BaseParser implements IParser {
}
}
myEncodeContext.popPath();
if (myDef != null) {
myEncodeContext.popPath();
}
return retVal;
}

View File

@ -212,7 +212,7 @@ public interface IParser {
* The elements to encode
* @see #setEncodeElements(Set)
*/
void setDontEncodeElements(Set<String> theDontEncodeElements);
IParser setDontEncodeElements(Set<String> theDontEncodeElements);
/**
* If provided, specifies the elements which should be encoded, to the exclusion of all others. Valid values for this
@ -230,7 +230,7 @@ public interface IParser {
* The elements to encode
* @see #setDontEncodeElements(Set)
*/
void setEncodeElements(Set<String> theEncodeElements);
IParser setEncodeElements(Set<String> theEncodeElements);
/**
* If set to <code>true</code> (default is false), the values supplied

View File

@ -84,15 +84,21 @@ public class AttachmentUtil {
}
}
/**
* This is internal API- Use with caution as it may change
*/
@SuppressWarnings("unchecked")
private static <T> IPrimitiveType<T> newPrimitive(FhirContext theContext, String theType, T theValue) {
static <T> IPrimitiveType<T> newPrimitive(FhirContext theContext, String theType, T theValue) {
IPrimitiveType<T> primitive = (IPrimitiveType<T>) theContext.getElementDefinition(theType).newInstance();
primitive.setValue(theValue);
return primitive;
}
private static BaseRuntimeChildDefinition getChild(FhirContext theContext, ICompositeType theAttachment, String theName) {
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theAttachment.getClass());
/**
* This is internal API- Use with caution as it may change
*/
static BaseRuntimeChildDefinition getChild(FhirContext theContext, IBase theElement, String theName) {
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theElement.getClass());
return def.getChildByName(theName);
}
}

View File

@ -20,13 +20,8 @@ package ca.uhn.fhir.util;
* #L%
*/
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseReference;
import ca.uhn.fhir.context.*;
import org.hl7.fhir.instance.model.api.*;
import java.util.List;
@ -36,6 +31,31 @@ public class BinaryUtil {
// non instantiable
}
/**
* Fetches the base64Binary value of Binary.data (or Binary.content on versions of
* FHIR before R4), creating it if it does not already exist.
*/
@SuppressWarnings("unchecked")
public static IPrimitiveType<byte[]> getOrCreateData(FhirContext theContext, IBaseBinary theBinary) {
String elementName = "content";
if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
elementName = "data";
}
BaseRuntimeChildDefinition entryChild = AttachmentUtil.getChild(theContext, theBinary, elementName);
List<IBase> entries = entryChild.getAccessor().getValues(theBinary);
return entries
.stream()
.map(t -> (IPrimitiveType<byte[]>) t)
.findFirst()
.orElseGet(() -> {
IPrimitiveType<byte[]> binary = AttachmentUtil.newPrimitive(theContext, "base64Binary", null);
entryChild.getMutator().setValue(theBinary, binary);
return binary;
});
}
public static IBaseReference getSecurityContext(FhirContext theCtx, IBaseBinary theBinary) {
RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
BaseRuntimeChildDefinition child = def.getChildByName("securityContext");

View File

@ -0,0 +1,49 @@
package ca.uhn.fhir.util;
import com.google.common.io.CountingInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountingAndLimitingInputStream extends InputStream {
private final int myMaxBytes;
private final CountingInputStream myWrap;
@Override
public int read() throws IOException {
int retVal = myWrap.read();
validateCount();
return retVal;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int retVal = myWrap.read(b, off, len);
validateCount();
return retVal;
}
@Override
public int read(byte[] theRead) throws IOException {
int retVal = myWrap.read(theRead);
validateCount();
return retVal;
}
private void validateCount() throws IOException {
if (myWrap.getCount() > myMaxBytes) {
throw new IOException("Stream exceeds maximum allowable size: " + myMaxBytes);
}
}
/**
* Wraps another input stream, counting the number of bytes read.
*
* @param theWrap the input stream to be wrapped
*/
public CountingAndLimitingInputStream(InputStream theWrap, int theMaxBytes) {
myWrap = new CountingInputStream(theWrap);
myMaxBytes = theMaxBytes;
}
}

View File

@ -34,4 +34,7 @@ public interface IBaseBinary extends IBaseResource {
IBaseBinary setContentAsBase64(String theContent);
IBaseBinary setContentType(String theContentType);
default boolean hasData() { return getContent() != null && getContent().length > 0; };
}

View File

@ -116,8 +116,11 @@ ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor.successMsg=Cascaded delet
ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor.noParam=Note that cascading deletes are not active for this request. You can enable cascading deletes by using the "_cascade=true" URL parameter.
ca.uhn.fhir.jpa.provider.BaseJpaProvider.cantCombintAtAndSince=Unable to combine _at and _since parameters for history operation
ca.uhn.fhir.jpa.provider.BinaryAccessProvider.noAttachmentDataPresent=The resource with ID {0} has no data at path: {1}
ca.uhn.fhir.jpa.provider.BinaryAccessProvider.unknownBlobId=Can not find the requested binary content. It may have been deleted.
ca.uhn.fhir.jpa.binstore.BinaryAccessProvider.noAttachmentDataPresent=The resource with ID {0} has no data at path: {1}
ca.uhn.fhir.jpa.binstore.BinaryAccessProvider.unknownBlobId=Can not find the requested binary content. It may have been deleted.
ca.uhn.fhir.jpa.binstore.BinaryAccessProvider.unknownPath=Unable to find content in resource of type {0} at path: {1}
ca.uhn.fhir.jpa.binstore.BinaryAccessProvider.unknownType=Content in resource of type {0} at path {1} is not appropriate for binary storage: {2}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUrl=Can not create multiple CodeSystem resources with CodeSystem.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}

View File

@ -294,7 +294,7 @@ public class GenericOkHttpClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
@ -304,7 +304,7 @@ public class GenericOkHttpClientDstu2Test {
p.setId("123");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
String body = ourRequestBodyString;
@ -323,7 +323,7 @@ public class GenericOkHttpClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.create().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
String expectedContentTypeHeader = EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8;
assertContentTypeEquals(expectedContentTypeHeader);
@ -332,7 +332,7 @@ public class GenericOkHttpClientDstu2Test {
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();
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(expectedContentTypeHeader);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -340,7 +340,7 @@ public class GenericOkHttpClientDstu2Test {
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();
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(expectedContentTypeHeader);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -528,6 +528,7 @@ public class GenericOkHttpClientDstu2Test {
.add()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta-add", ourRequestUri);
@ -761,7 +762,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
@ -792,6 +793,7 @@ public class GenericOkHttpClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new StringDt("value1"))
.andParameter("name2", new StringDt("value1"))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -813,6 +815,7 @@ public class GenericOkHttpClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
.andParameter("name2", new StringDt("value1"))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -834,6 +837,7 @@ public class GenericOkHttpClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
.andParameter("name2", new Patient().setActive(true))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -915,6 +919,7 @@ public class GenericOkHttpClientDstu2Test {
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeDt("8495-4"))
.andParameter("system", new UriDt("http://loinc.org"))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/1/$validate-code", ourRequestUri);
@ -947,7 +952,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -960,7 +965,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -973,7 +978,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1008,7 +1013,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1021,7 +1026,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1034,7 +1039,7 @@ public class GenericOkHttpClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1653,35 +1658,35 @@ public class GenericOkHttpClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("PUT", ourRequestMethod);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
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();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
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();
client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
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();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertContentTypeEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1698,6 +1703,7 @@ public class GenericOkHttpClientDstu2Test {
ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
@ -1708,14 +1714,14 @@ public class GenericOkHttpClientDstu2Test {
String expectedContentTypeHeader = EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8;
assertThat(getActualContentTypeHeader(), equalToIgnoringCase(expectedContentTypeHeader));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
client.update("123", p);
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertThat(getActualContentTypeHeader(), equalToIgnoringCase(expectedContentTypeHeader));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
}
@ -1775,7 +1781,7 @@ public class GenericOkHttpClientDstu2Test {
MethodOutcome response;
response = client.validate().resource(p).execute();
response = client.validate().resource(p).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals(
@ -1818,6 +1824,7 @@ public class GenericOkHttpClientDstu2Test {
ourResponseBody = msg;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
Patient p = new Patient();
p.addName().addGiven("GIVEN");
@ -1826,7 +1833,7 @@ public class GenericOkHttpClientDstu2Test {
response = client.validate(p);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=xml", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",

View File

@ -72,7 +72,7 @@ public abstract class BaseClient implements IRestfulClient {
private final RestfulClientFactory myFactory;
private final String myUrlBase;
private boolean myDontValidateConformance;
private EncodingEnum myEncoding = null; // default unspecified (will be XML)
private EncodingEnum myEncoding = null; // default unspecified (will be JSON)
private boolean myKeepResponses = false;
private IHttpResponse myLastResponse;
private String myLastResponseBody;

View File

@ -116,7 +116,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
if (myResource != null && IBaseBinary.class.isAssignableFrom(myResource.getClass())) {
IBaseBinary binary = (IBaseBinary) myResource;
if (isNotBlank(binary.getContentType()) && EncodingEnum.forContentTypeStrict(binary.getContentType()) == null) {
return httpClient.createBinaryRequest(getContext(), binary);
if (binary.hasData()) {
return httpClient.createBinaryRequest(getContext(), binary);
}
}
}
@ -129,7 +131,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
if (myParams != null) {
return httpClient.createParamRequest(getContext(), myParams, encoding);
}
encoding = ObjectUtils.defaultIfNull(encoding, EncodingEnum.XML);
encoding = ObjectUtils.defaultIfNull(encoding, EncodingEnum.JSON);
String contents = encodeContents(thePrettyPrint, encoding);
String contentType = getContentType(encoding);
return httpClient.createByteRequest(getContext(), contents, contentType, encoding);

View File

@ -221,7 +221,7 @@ public class GenericJaxRsClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
@ -232,7 +232,7 @@ public class GenericJaxRsClientDstu2Test {
p.setId("123");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
String body = ourRequestBodyString;
@ -257,7 +257,7 @@ public class GenericJaxRsClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.create().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -266,7 +266,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals("POST", ourRequestMethod);
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -275,7 +275,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals("POST", ourRequestMethod);
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).execute();
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -495,6 +495,7 @@ public class GenericJaxRsClientDstu2Test {
.add()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta-add", ourRequestUri);
@ -766,7 +767,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
@ -801,6 +802,7 @@ public class GenericJaxRsClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new StringDt("value1"))
.andParameter("name2", new StringDt("value1"))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -822,6 +824,7 @@ public class GenericJaxRsClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
.andParameter("name2", new StringDt("value1"))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -844,6 +847,7 @@ public class GenericJaxRsClientDstu2Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new IdentifierDt("system1", "value1"))
.andParameter("name2", new Patient().setActive(true))
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -937,6 +941,8 @@ public class GenericJaxRsClientDstu2Test {
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeDt("8495-4"))
.andParameter("system", new UriDt("http://loinc.org"))
.encodedXml()
.encodedXml()
.execute();
@ -975,7 +981,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -990,7 +996,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1005,7 +1011,9 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1048,7 +1056,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1063,7 +1071,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1078,7 +1086,7 @@ public class GenericJaxRsClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1833,7 +1841,7 @@ public class GenericJaxRsClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1841,7 +1849,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1849,7 +1857,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar", ourRequestUri);
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1857,7 +1865,7 @@ public class GenericJaxRsClientDstu2Test {
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();
client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1865,7 +1873,7 @@ public class GenericJaxRsClientDstu2Test {
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();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1882,7 +1890,7 @@ public class GenericJaxRsClientDstu2Test {
ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
Patient p = new Patient();
@ -1892,7 +1900,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
@ -1900,7 +1908,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
}
@ -1975,7 +1983,7 @@ public class GenericJaxRsClientDstu2Test {
MethodOutcome response;
response = client.validate().resource(p).execute();
response = client.validate().resource(p).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", ourRequestBodyString);
@ -1983,7 +1991,7 @@ public class GenericJaxRsClientDstu2Test {
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute();
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", ourRequestBodyString);
@ -2018,6 +2026,7 @@ public class GenericJaxRsClientDstu2Test {
ourResponseBody = msg;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
Patient p = new Patient();
p.addName().addGiven("GIVEN");
@ -2029,7 +2038,7 @@ public class GenericJaxRsClientDstu2Test {
response = client.validate(p);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=xml", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", ourRequestBodyString);
assertNotNull(response.getOperationOutcome());

View File

@ -222,7 +222,7 @@ public class GenericJaxRsClientDstu3Test {
Patient p = new Patient();
p.addName().setFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
@ -233,7 +233,7 @@ public class GenericJaxRsClientDstu3Test {
p.setId("123");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
String body = ourRequestBodyString;
@ -258,7 +258,7 @@ public class GenericJaxRsClientDstu3Test {
Patient p = new Patient();
p.addName().setFamily("FOOFAMILY");
client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.create().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -267,7 +267,7 @@ public class GenericJaxRsClientDstu3Test {
assertEquals("POST", ourRequestMethod);
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -276,7 +276,7 @@ public class GenericJaxRsClientDstu3Test {
assertEquals("POST", ourRequestMethod);
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).execute();
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -298,7 +298,7 @@ public class GenericJaxRsClientDstu3Test {
Patient p = new Patient();
p.addName().setFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
@ -515,6 +515,7 @@ public class GenericJaxRsClientDstu3Test {
.add()
.onResource(new IdType("Patient/123"))
.meta(inMeta)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta-add", ourRequestUri);
@ -786,7 +787,9 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
@ -821,6 +824,7 @@ public class GenericJaxRsClientDstu3Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new StringType("value1"))
.andParameter("name2", new StringType("value1"))
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -842,6 +846,7 @@ public class GenericJaxRsClientDstu3Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new Identifier().setSystem("system1").setValue("value1"))
.andParameter("name2", new StringType("value1"))
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -864,6 +869,7 @@ public class GenericJaxRsClientDstu3Test {
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new Identifier().setSystem("system1").setValue("value1"))
.andParameter("name2", new Patient().setActive(true))
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
@ -957,6 +963,7 @@ public class GenericJaxRsClientDstu3Test {
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://loinc.org"))
.encodedXml()
.execute();
//@formatter:off
@ -995,7 +1002,9 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1010,7 +1019,9 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1025,7 +1036,9 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onInstance(new IdType("Patient", "123"))
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1068,7 +1081,7 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1083,7 +1096,7 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class).encodedXml().execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1098,7 +1111,9 @@ public class GenericJaxRsClientDstu3Test {
.operation()
.onInstance(new IdType("Patient", "123"))
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri);
assertEquals(respString, p.encodeResourceToString(resp));
@ -1878,7 +1893,7 @@ public class GenericJaxRsClientDstu3Test {
Patient p = new Patient();
p.addName().setFamily("FOOFAMILY");
client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1886,7 +1901,7 @@ public class GenericJaxRsClientDstu3Test {
assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri);
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1902,7 +1917,7 @@ public class GenericJaxRsClientDstu3Test {
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();
client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1910,7 +1925,7 @@ public class GenericJaxRsClientDstu3Test {
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();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
@ -1927,6 +1942,7 @@ public class GenericJaxRsClientDstu3Test {
ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
@ -1937,7 +1953,7 @@ public class GenericJaxRsClientDstu3Test {
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
@ -1945,7 +1961,7 @@ public class GenericJaxRsClientDstu3Test {
assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char"));
assertThat(ourRequestBodyString, containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=xml", ourRequestUri);
assertEquals("PUT", ourRequestMethod);
}
@ -2020,7 +2036,7 @@ public class GenericJaxRsClientDstu3Test {
MethodOutcome response;
response = client.validate().resource(p).execute();
response = client.validate().resource(p).encodedXml().execute();
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", ourRequestBodyString);
@ -2063,6 +2079,7 @@ public class GenericJaxRsClientDstu3Test {
ourResponseBody = msg;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
client.setEncoding(EncodingEnum.XML);
Patient p = new Patient();
p.addName().addGiven("GIVEN");
@ -2074,7 +2091,7 @@ public class GenericJaxRsClientDstu3Test {
response = client.validate(p);
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri);
assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=xml", ourRequestUri);
assertEquals("POST", ourRequestMethod);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", ourRequestBodyString);
assertNotNull(response.getOperationOutcome());

View File

@ -23,6 +23,9 @@ package ca.uhn.fhir.jpa.binstore;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.hash.HashingInputStream;
import com.google.common.io.ByteStreams;
import com.google.common.io.CountingInputStream;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IIdType;
import javax.annotation.Nonnull;
@ -30,18 +33,35 @@ import java.io.InputStream;
import java.security.SecureRandom;
abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc {
private final SecureRandom myRandom;
private final String CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private final int ID_LENGTH = 100;
private int myMinSize;
private int myMaximumBinarySize = Integer.MAX_VALUE;
private int myMinimumBinarySize;
BaseBinaryStorageSvcImpl() {
myRandom = new SecureRandom();
}
public void setMinSize(int theMinSize) {
myMinSize = theMinSize;
@Override
public int getMaximumBinarySize() {
return myMaximumBinarySize;
}
@Override
public int getMinimumBinarySize() {
return myMinimumBinarySize;
}
@Override
public void setMinimumBinarySize(int theMinimumBinarySize) {
myMinimumBinarySize = theMinimumBinarySize;
}
@Override
public void setMaximumBinarySize(int theMaximumBinarySize) {
Validate.inclusiveBetween(1, Integer.MAX_VALUE, theMaximumBinarySize);
myMaximumBinarySize = theMaximumBinarySize;
}
String newRandomId() {
@ -55,12 +75,22 @@ abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc {
@Override
public boolean shouldStoreBlob(long theSize, IIdType theResourceId, String theContentType) {
return theSize >= myMinSize;
return theSize >= getMinimumBinarySize();
}
@SuppressWarnings("UnstableApiUsage")
@Nonnull
static HashingInputStream createHashingInputStream(InputStream theInputStream) {
HashingInputStream createHashingInputStream(InputStream theInputStream) {
HashFunction hash = Hashing.sha256();
return new HashingInputStream(hash, theInputStream);
}
@SuppressWarnings("UnstableApiUsage")
@Nonnull
CountingInputStream createCountingInputStream(InputStream theInputStream) {
InputStream stream = ByteStreams.limit(theInputStream, myMaximumBinarySize);
return new CountingInputStream(stream);
}
}

View File

@ -0,0 +1,358 @@
package ca.uhn.fhir.jpa.binstore;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 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.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.DaoRegistry;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.AttachmentUtil;
import ca.uhn.fhir.util.BinaryUtil;
import ca.uhn.fhir.util.DateUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import static ca.uhn.fhir.util.UrlUtil.sanitizeUrlPart;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
* This plain provider class can be registered with a JPA RestfulServer
* to provide the <code>$binary-access-read</code> and <code>$binary-access-write</code>
* operations that can be used to access attachment data as a raw binary.
*/
public class BinaryAccessProvider {
@Autowired
private FhirContext myCtx;
@Autowired
private DaoRegistry myDaoRegistry;
@Autowired(required = false)
private IBinaryStorageSvc myBinaryStorageSvc;
/**
* $binary-access-read
*/
@Operation(name = JpaConstants.OPERATION_BINARY_ACCESS_READ, global = true, manualResponse = true, idempotent = true)
public void binaryAccessRead(
@IdParam IIdType theResourceId,
@OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath,
ServletRequestDetails theRequestDetails,
HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws IOException {
String path = validateResourceTypeAndPath(theResourceId, thePath);
IFhirResourceDao dao = getDaoForRequest(theResourceId);
IBaseResource resource = dao.read(theResourceId, theRequestDetails, false);
IBinaryTarget target = findAttachmentForRequest(resource, path, theRequestDetails);
Optional<? extends IBaseExtension<?, ?>> attachmentId = target
.getTarget()
.getExtension()
.stream()
.filter(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
.findFirst();
if (attachmentId.isPresent()) {
@SuppressWarnings("unchecked")
IPrimitiveType<String> value = (IPrimitiveType<String>) attachmentId.get().getValue();
String blobId = value.getValueAsString();
IBinaryStorageSvc.StoredDetails blobDetails = myBinaryStorageSvc.fetchBlobDetails(theResourceId, blobId);
if (blobDetails == null) {
String msg = myCtx.getLocalizer().getMessage(BinaryAccessProvider.class, "unknownBlobId");
throw new InvalidRequestException(msg);
}
theServletResponse.setStatus(200);
theServletResponse.setContentType(blobDetails.getContentType());
if (blobDetails.getBytes() <= Integer.MAX_VALUE) {
theServletResponse.setContentLength((int) blobDetails.getBytes());
}
RestfulServer server = theRequestDetails.getServer();
server.addHeadersToResponse(theServletResponse);
theServletResponse.addHeader(Constants.HEADER_CACHE_CONTROL, Constants.CACHE_CONTROL_PRIVATE);
theServletResponse.addHeader(Constants.HEADER_ETAG, '"' + blobDetails.getHash() + '"');
theServletResponse.addHeader(Constants.HEADER_LAST_MODIFIED, DateUtils.formatDate(blobDetails.getPublished()));
myBinaryStorageSvc.writeBlob(theResourceId, blobId, theServletResponse.getOutputStream());
theServletResponse.getOutputStream().close();
} else {
String contentType = target.getContentType();
contentType = StringUtils.defaultIfBlank(contentType, Constants.CT_OCTET_STREAM);
byte[] data = target.getData();
if (data == null) {
String msg = myCtx.getLocalizer().getMessage(BinaryAccessProvider.class, "noAttachmentDataPresent", sanitizeUrlPart(theResourceId), sanitizeUrlPart(thePath));
throw new InvalidRequestException(msg);
}
theServletResponse.setStatus(200);
theServletResponse.setContentType(contentType);
theServletResponse.setContentLength(data.length);
RestfulServer server = theRequestDetails.getServer();
server.addHeadersToResponse(theServletResponse);
theServletResponse.getOutputStream().write(data);
theServletResponse.getOutputStream().close();
}
}
/**
* $binary-access-write
*/
@SuppressWarnings("unchecked")
@Operation(name = JpaConstants.OPERATION_BINARY_ACCESS_WRITE, global = true, manualRequest = true, idempotent = false)
public IBaseResource binaryAccessWrite(
@IdParam IIdType theResourceId,
@OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath,
ServletRequestDetails theRequestDetails,
HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws IOException {
String path = validateResourceTypeAndPath(theResourceId, thePath);
IFhirResourceDao dao = getDaoForRequest(theResourceId);
IBaseResource resource = dao.read(theResourceId, theRequestDetails, false);
IBinaryTarget target = findAttachmentForRequest(resource, path, theRequestDetails);
String requestContentType = theServletRequest.getContentType();
if (isBlank(requestContentType)) {
throw new InvalidRequestException("No content-target supplied");
}
if (EncodingEnum.forContentTypeStrict(requestContentType) != null) {
throw new InvalidRequestException("This operation is for binary content, got: " + requestContentType);
}
long size = theServletRequest.getContentLength();
String blobId = null;
if (size > 0) {
if (myBinaryStorageSvc != null) {
if (myBinaryStorageSvc.shouldStoreBlob(size, theResourceId, requestContentType)) {
IBinaryStorageSvc.StoredDetails storedDetails = myBinaryStorageSvc.storeBlob(theResourceId, requestContentType, theRequestDetails.getInputStream());
size = storedDetails.getBytes();
blobId = storedDetails.getBlobId();
Validate.notBlank(blobId, "BinaryStorageSvc returned a null blob ID"); // should not happen
}
}
}
if (blobId == null) {
byte[] bytes = IOUtils.toByteArray(theRequestDetails.getInputStream());
size = bytes.length;
target.setData(bytes);
} else {
target
.getTarget()
.getExtension()
.removeIf(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()));
target.setData(null);
IBaseExtension<?, ?> ext = target.getTarget().addExtension();
ext.setUrl(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
IPrimitiveType<String> blobIdString = (IPrimitiveType<String>) myCtx.getElementDefinition("string").newInstance();
blobIdString.setValueAsString(blobId);
ext.setValue(blobIdString);
}
target.setContentType(requestContentType);
target.setSize(null);
if (size <= Integer.MAX_VALUE) {
target.setSize((int) size);
}
DaoMethodOutcome outcome = dao.update(resource, theRequestDetails);
return outcome.getResource();
}
@Nonnull
private IBinaryTarget findAttachmentForRequest(IBaseResource theResource, String thePath, ServletRequestDetails theRequestDetails) {
FhirContext ctx = theRequestDetails.getFhirContext();
Optional<IBase> type = ctx.newFluentPath().evaluateFirst(theResource, thePath, IBase.class);
String resType = myCtx.getResourceDefinition(theResource).getName();
if (!type.isPresent()) {
String msg = myCtx.getLocalizer().getMessageSanitized(BinaryAccessProvider.class, "unknownPath", resType, thePath);
throw new InvalidRequestException(msg);
}
// Path is attachment
BaseRuntimeElementDefinition<?> def = ctx.getElementDefinition(type.get().getClass());
if (def.getName().equals("Attachment")) {
ICompositeType attachment = (ICompositeType) type.get();
return new IBinaryTarget() {
@Override
public void setSize(Integer theSize) {
AttachmentUtil.setSize(myCtx, attachment, theSize);
}
@Override
public String getContentType() {
return AttachmentUtil.getOrCreateContentType(myCtx, attachment).getValueAsString();
}
@Override
public byte[] getData() {
IPrimitiveType<byte[]> dataDt = AttachmentUtil.getOrCreateData(theRequestDetails.getFhirContext(), attachment);
return dataDt.getValue();
}
@Override
public IBaseHasExtensions getTarget() {
return (IBaseHasExtensions) AttachmentUtil.getOrCreateData(theRequestDetails.getFhirContext(), attachment);
}
@Override
public void setContentType(String theContentType) {
AttachmentUtil.setContentType(myCtx, attachment, theContentType);
}
@Override
public void setData(byte[] theBytes) {
AttachmentUtil.setData(theRequestDetails.getFhirContext(), attachment, theBytes);
}
};
}
// Path is Binary
if (def.getName().equals("Binary")) {
IBaseBinary binary = (IBaseBinary) type.get();
return new IBinaryTarget() {
@Override
public void setSize(Integer theSize) {
// ignore
}
@Override
public String getContentType() {
return binary.getContentType();
}
@Override
public byte[] getData() {
return binary.getContent();
}
@Override
public IBaseHasExtensions getTarget() {
return (IBaseHasExtensions) BinaryUtil.getOrCreateData(myCtx, binary);
}
@Override
public void setContentType(String theContentType) {
binary.setContentType(theContentType);
}
@Override
public void setData(byte[] theBytes) {
binary.setContent(theBytes);
}
};
}
String msg = myCtx.getLocalizer().getMessageSanitized(BinaryAccessProvider.class, "unknownType", resType, thePath, def.getName());
throw new InvalidRequestException(msg);
}
private String validateResourceTypeAndPath(@IdParam IIdType theResourceId, @OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath) {
if (isBlank(theResourceId.getResourceType())) {
throw new InvalidRequestException("No resource type specified");
}
if (isBlank(theResourceId.getIdPart())) {
throw new InvalidRequestException("No ID specified");
}
if (thePath == null || isBlank(thePath.getValue())) {
if ("Binary".equals(theResourceId.getResourceType())) {
return "Binary";
}
throw new InvalidRequestException("No path specified");
}
return thePath.getValue();
}
@Nonnull
private IFhirResourceDao getDaoForRequest(@IdParam IIdType theResourceId) {
String resourceType = theResourceId.getResourceType();
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceType);
if (dao == null) {
throw new InvalidRequestException("Unknown/unsupported resource type: " + sanitizeUrlPart(resourceType));
}
return dao;
}
/**
* Wraps an Attachment datatype or Binary resource, since they both
* hold binary content but don't look entirely similar
*/
private interface IBinaryTarget {
void setSize(Integer theSize);
String getContentType();
void setContentType(String theContentType);
byte[] getData();
void setData(byte[] theBytes);
IBaseHasExtensions getTarget();
}
}

View File

@ -0,0 +1,44 @@
package ca.uhn.fhir.jpa.binstore;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.stream.Collectors;
@Interceptor
public class BinaryStorageInterceptor {
@Autowired
private IBinaryStorageSvc myBinaryStorageSvc;
@Autowired
private FhirContext myCtx;
@Hook(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE)
public void expungeResource(IBaseResource theResource) {
Class<? extends IBase> binaryType = myCtx.getElementDefinition("base64Binary").getImplementingClass();
List<? extends IBase> binaryElements = myCtx.newTerser().getAllPopulatedChildElementsOfType(theResource, binaryType);
List<String> attachmentIds = binaryElements
.stream()
.flatMap(t -> ((IBaseHasExtensions) t).getExtension().stream())
.filter(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
.map(t -> ((IPrimitiveType) t.getValue()).getValueAsString())
.collect(Collectors.toList());
for (String next : attachmentIds) {
myBinaryStorageSvc.expungeBlob(theResource.getIdElement(), next);
}
}
}

View File

@ -0,0 +1,124 @@
package ca.uhn.fhir.jpa.binstore;
import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao;
import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity;
import com.google.common.hash.HashingInputStream;
import com.google.common.io.CountingInputStream;
import org.apache.commons.io.IOUtils;
import org.hibernate.LobHelper;
import org.hibernate.Session;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.transaction.Transactional;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.Date;
import java.util.Optional;
@Transactional
public class DatabaseBlobBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
private EntityManager myEntityManager;
@Autowired
private IBinaryStorageEntityDao myBinaryStorageEntityDao;
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
@Override
@Transactional(Transactional.TxType.SUPPORTS)
public StoredDetails storeBlob(IIdType theResourceId, String theContentType, InputStream theInputStream) throws IOException {
Date publishedDate = new Date();
HashingInputStream hashingInputStream = createHashingInputStream(theInputStream);
CountingInputStream countingInputStream = createCountingInputStream(hashingInputStream);
String id = newRandomId();
BinaryStorageEntity entity = new BinaryStorageEntity();
entity.setResourceId(theResourceId.toUnqualifiedVersionless().getValue());
entity.setBlobId(id);
entity.setBlobContentType(theContentType);
entity.setPublished(publishedDate);
Session session = (Session) myEntityManager.getDelegate();
LobHelper lobHelper = session.getLobHelper();
Blob dataBlob = lobHelper.createBlob(countingInputStream, 0);
entity.setBlob(dataBlob);
// Save the entity
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(t->{
myEntityManager.persist(entity);
return null;
});
// Update the entity with the final byte count and hash
long bytes = countingInputStream.getCount();
String hash = hashingInputStream.hash().toString();
txTemplate.execute(t-> {
myBinaryStorageEntityDao.setSize(id, (int) bytes);
myBinaryStorageEntityDao.setHash(id, hash);
return null;
});
return new StoredDetails()
.setBlobId(id)
.setBytes(bytes)
.setPublished(publishedDate)
.setHash(hash)
.setContentType(theContentType);
}
@Override
public StoredDetails fetchBlobDetails(IIdType theResourceId, String theBlobId) throws IOException {
Optional<BinaryStorageEntity> entityOpt = myBinaryStorageEntityDao.findByIdAndResourceId(theBlobId, theResourceId.toUnqualifiedVersionless().getValue());
if (entityOpt.isPresent() == false) {
return null;
}
BinaryStorageEntity entity = entityOpt.get();
return new StoredDetails()
.setBlobId(theBlobId)
.setContentType(entity.getBlobContentType())
.setHash(entity.getHash())
.setPublished(entity.getPublished())
.setBytes(entity.getSize());
}
@Override
public boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException {
Optional<BinaryStorageEntity> entityOpt = myBinaryStorageEntityDao.findByIdAndResourceId(theBlobId, theResourceId.toUnqualifiedVersionless().getValue());
if (entityOpt.isPresent() == false) {
return false;
}
try {
InputStream inputStream = entityOpt.get().getBlob().getBinaryStream();
IOUtils.copy(inputStream, theOutputStream);
} catch (SQLException e) {
throw new IOException(e);
}
return true;
}
@Override
public void expungeBlob(IIdType theResourceId, String theBlobId) {
Optional<BinaryStorageEntity> entityOpt = myBinaryStorageEntityDao.findByIdAndResourceId(theBlobId, theResourceId.toUnqualifiedVersionless().getValue());
entityOpt.ifPresent(theBinaryStorageEntity -> myBinaryStorageEntityDao.delete(theBinaryStorageEntity));
}
}

View File

@ -70,7 +70,7 @@ public class FilesystemBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
// Write binary file
File storageFilename = getStorageFilename(storagePath, theResourceId, id);
ourLog.info("Writing to file: {}", storageFilename.getAbsolutePath());
CountingInputStream countingInputStream = new CountingInputStream(theInputStream);
CountingInputStream countingInputStream = createCountingInputStream(theInputStream);
HashingInputStream hashingInputStream = createHashingInputStream(countingInputStream);
try (FileOutputStream outputStream = new FileOutputStream(storageFilename)) {
IOUtils.copy(hashingInputStream, outputStream);
@ -110,7 +110,7 @@ public class FilesystemBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
}
@Override
public void writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException {
public boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException {
File storagePath = getStoragePath(theBlobId, false);
if (storagePath != null) {
File file = getStorageFilename(storagePath, theResourceId, theBlobId);
@ -121,6 +121,26 @@ public class FilesystemBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
}
}
}
return false;
}
@Override
public void expungeBlob(IIdType theResourceId, String theBlobId) {
File storagePath = getStoragePath(theBlobId, false);
if (storagePath != null) {
File storageFile = getStorageFilename(storagePath, theResourceId, theBlobId);
if (storageFile.exists()) {
delete(storageFile, theBlobId);
}
File descriptorFile = getDescriptorFilename(storagePath, theResourceId, theBlobId);
if (descriptorFile.exists()) {
delete(descriptorFile, theBlobId);
}
}
}
private void delete(File theStorageFile, String theBlobId) {
Validate.isTrue(theStorageFile.delete(), "Failed to delete file for blob %s", theBlobId);
}
@Nonnull

View File

@ -39,6 +39,34 @@ import java.util.Date;
public interface IBinaryStorageSvc {
/**
* Gets the maximum number of bytes that can be stored in a single binary
* file by this service. The default is {@link Integer#MAX_VALUE}
*/
int getMaximumBinarySize();
/**
* Sets the maximum number of bytes that can be stored in a single binary
* file by this service. The default is {@link Integer#MAX_VALUE}
*
* @param theMaximumBinarySize The maximum size
*/
void setMaximumBinarySize(int theMaximumBinarySize);
/**
* Gets the minimum number of bytes that will be stored. Binary content smaller
* * than this threshold may be inlined even if a binary storage service
* * is active.
*/
int getMinimumBinarySize();
/**
* Sets the minimum number of bytes that will be stored. Binary content smaller
* than this threshold may be inlined even if a binary storage service
* is active.
*/
void setMinimumBinarySize(int theMinimumBinarySize);
/**
* Give the storage service the ability to veto items from storage
*
@ -61,7 +89,12 @@ public interface IBinaryStorageSvc {
StoredDetails fetchBlobDetails(IIdType theResourceId, String theBlobId) throws IOException;
void writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException;
/**
* @return Returns <code>true</code> if the blob was found and written, of <code>false</code> if the blob was not found (i.e. it was expunged or the ID was invalid)
*/
boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException;
void expungeBlob(IIdType theResourceId, String theBlobId);
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -115,23 +148,48 @@ public interface IBinaryStorageSvc {
return myHash;
}
public StoredDetails setHash(String theHash) {
myHash = theHash;
return this;
}
public Date getPublished() {
return myPublished;
}
public StoredDetails setPublished(Date thePublished) {
myPublished = thePublished;
return this;
}
@Nonnull
public String getContentType() {
return myContentType;
}
public StoredDetails setContentType(String theContentType) {
myContentType = theContentType;
return this;
}
@Nonnull
public String getBlobId() {
return myBlobId;
}
public StoredDetails setBlobId(String theBlobId) {
myBlobId = theBlobId;
return this;
}
public long getBytes() {
return myBytes;
}
public StoredDetails setBytes(long theBytes) {
myBytes = theBytes;
return this;
}
}
}

View File

@ -69,10 +69,20 @@ public class MemoryBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl impleme
}
@Override
public void writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException {
public boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException {
String key = toKey(theResourceId, theBlobId);
byte[] bytes = myDataMap.get(key);
if (bytes == null) {
return false;
}
theOutputStream.write(bytes);
return true;
}
@Override
public void expungeBlob(IIdType theResourceId, String theBlobId) {
String key = toKey(theResourceId, theBlobId);
myDataMap.remove(key);
}
private String toKey(IIdType theResourceId, String theBlobId) {

View File

@ -22,13 +22,31 @@ package ca.uhn.fhir.jpa.binstore;
import org.hl7.fhir.instance.model.api.IIdType;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
public class NullBinaryStorageSvcImpl implements IBinaryStorageSvc {
@Override
public int getMaximumBinarySize() {
return 0;
}
@Override
public void setMaximumBinarySize(int theMaximumBinarySize) {
// ignore
}
@Override
public int getMinimumBinarySize() {
return 0;
}
@Override
public void setMinimumBinarySize(int theMinimumBinarySize) {
// ignore
}
@Override
public boolean shouldStoreBlob(long theSize, IIdType theResourceId, String theContentType) {
return false;
@ -45,7 +63,12 @@ public class NullBinaryStorageSvcImpl implements IBinaryStorageSvc {
}
@Override
public void writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) {
public boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) {
throw new UnsupportedOperationException();
}
@Override
public void expungeBlob(IIdType theIdElement, String theBlobId) {
throw new UnsupportedOperationException();
}
}

View File

@ -4,9 +4,10 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.executor.InterceptorService;
import ca.uhn.fhir.jpa.binstore.BinaryAccessProvider;
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.dao.DaoRegistry;
import ca.uhn.fhir.jpa.interceptor.JpaConsentContextServices;
import ca.uhn.fhir.jpa.provider.BinaryAccessProvider;
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
@ -123,10 +124,16 @@ public abstract class BaseConfig implements SchedulingConfigurer {
@Bean(name = "myAttachmentBinaryAccessProvider")
@Lazy
public BinaryAccessProvider AttachmentBinaryAccessProvider() {
public BinaryAccessProvider binaryAccessProvider() {
return new BinaryAccessProvider();
}
@Bean(name = "myBinaryStorageInterceptor")
@Lazy
public BinaryStorageInterceptor binaryStorageInterceptor() {
return new BinaryStorageInterceptor();
}
@Bean
public TaskScheduler taskScheduler() {
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();

View File

@ -0,0 +1,23 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
public interface IBinaryStorageEntityDao extends JpaRepository<BinaryStorageEntity, String> {
@Modifying
@Query("UPDATE BinaryStorageEntity e SET e.mySize = :blob_size WHERE e.myBlobId = :blob_id")
void setSize(@Param("blob_id") String theId, @Param("blob_size") int theBytes);
@Modifying
@Query("UPDATE BinaryStorageEntity e SET e.myHash = :blob_hash WHERE e.myBlobId = :blob_id")
void setHash(@Param("blob_id") String theId, @Param("blob_hash") String theHash);
@Query("SELECT e FROM BinaryStorageEntity e WHERE e.myBlobId = :blob_id AND e.myResourceId = :resource_id")
Optional<BinaryStorageEntity> findByIdAndResourceId(@Param("blob_id") String theBlobId, @Param("resource_id") String theResourceId);
}

View File

@ -112,15 +112,15 @@ public class ExpungeRun implements Callable<ExpungeOutcome> {
private void expungeOldVersions() {
Slice<Long> historicalIds = findHistoricalVersionsOfNonDeletedResources();
myPartitionRunner.runInPartitionedThreads(historicalIds, partition -> myExpungeDaoService.expungeHistoricalVersions(partition, myRemainingCount));
myPartitionRunner.runInPartitionedThreads(historicalIds, partition -> myExpungeDaoService.expungeHistoricalVersions(myRequestDetails, partition, myRemainingCount));
}
private void deleteCurrentVersionsOfDeletedResources(Slice<Long> theResourceIds) {
myPartitionRunner.runInPartitionedThreads(theResourceIds, partition -> myExpungeDaoService.expungeCurrentVersionOfResources(partition, myRemainingCount));
myPartitionRunner.runInPartitionedThreads(theResourceIds, partition -> myExpungeDaoService.expungeCurrentVersionOfResources(myRequestDetails, partition, myRemainingCount));
}
private void deleteHistoricalVersions(Slice<Long> theResourceIds) {
myPartitionRunner.runInPartitionedThreads(theResourceIds, partition -> myExpungeDaoService.expungeHistoricalVersionsOfIds(partition, myRemainingCount));
myPartitionRunner.runInPartitionedThreads(theResourceIds, partition -> myExpungeDaoService.expungeHistoricalVersionsOfIds(myRequestDetails, partition, myRemainingCount));
}
private void deleteSearchResultCacheEntries(Slice<Long> theResourceIds) {

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.expunge;
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.springframework.data.domain.Slice;
import java.util.List;
@ -30,11 +31,11 @@ public interface IResourceExpungeService {
Slice<Long> findHistoricalVersionsOfNonDeletedResources(String theResourceName, Long theResourceId, Long theVersion, int theI);
void expungeHistoricalVersions(List<Long> thePartition, AtomicInteger theRemainingCount);
void expungeHistoricalVersions(RequestDetails theRequestDetails, List<Long> thePartition, AtomicInteger theRemainingCount);
void expungeCurrentVersionOfResources(List<Long> thePartition, AtomicInteger theRemainingCount);
void expungeCurrentVersionOfResources(RequestDetails theRequestDetails, List<Long> thePartition, AtomicInteger theRemainingCount);
void expungeHistoricalVersionsOfIds(List<Long> thePartition, AtomicInteger theRemainingCount);
void expungeHistoricalVersionsOfIds(RequestDetails theRequestDetails, List<Long> thePartition, AtomicInteger theRemainingCount);
void deleteByResourceIdPartitions(List<Long> thePartition);

View File

@ -20,12 +20,23 @@ package ca.uhn.fhir.jpa.dao.expunge;
* #L%
*/
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.dao.DaoRegistry;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -72,6 +83,10 @@ class ResourceExpungeService implements IResourceExpungeService {
private IdHelperService myIdHelperService;
@Autowired
private IResourceHistoryTagDao myResourceHistoryTagDao;
@Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster;
@Autowired
private DaoRegistry myDaoRegistry;
@Override
@Transactional
@ -115,18 +130,31 @@ class ResourceExpungeService implements IResourceExpungeService {
@Override
@Transactional
public void expungeCurrentVersionOfResources(List<Long> theResourceIds, AtomicInteger theRemainingCount) {
public void expungeCurrentVersionOfResources(RequestDetails theRequestDetails, List<Long> theResourceIds, AtomicInteger theRemainingCount) {
for (Long next : theResourceIds) {
expungeCurrentVersionOfResource(next, theRemainingCount);
expungeCurrentVersionOfResource(theRequestDetails, next, theRemainingCount);
if (theRemainingCount.get() <= 0) {
return;
}
}
}
private void expungeHistoricalVersion(Long theNextVersionId) {
private void expungeHistoricalVersion(RequestDetails theRequestDetails, Long theNextVersionId) {
ResourceHistoryTable version = myResourceHistoryTableDao.findById(theNextVersionId).orElseThrow(IllegalArgumentException::new);
ourLog.info("Deleting resource version {}", version.getIdDt().getValue());
IdDt id = version.getIdDt();
ourLog.info("Deleting resource version {}", id.getValue());
// Interceptor call: STORAGE_PRESTORAGE_EXPUNGE_RESOURCE
if (JpaInterceptorBroadcaster.hasHooks(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, myInterceptorBroadcaster, theRequestDetails)) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(id.getResourceType());
IBaseResource resource = resourceDao.toResource(version, false);
HookParams params = new HookParams()
.add(IIdType.class, id)
.add(IBaseResource.class, resource)
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, params);
}
myResourceHistoryTagDao.deleteAll(version.getTags());
myResourceHistoryTableDao.delete(version);
@ -134,9 +162,9 @@ class ResourceExpungeService implements IResourceExpungeService {
@Override
@Transactional
public void expungeHistoricalVersionsOfIds(List<Long> theResourceIds, AtomicInteger theRemainingCount) {
public void expungeHistoricalVersionsOfIds(RequestDetails theRequestDetails, List<Long> theResourceIds, AtomicInteger theRemainingCount) {
for (Long next : theResourceIds) {
expungeHistoricalVersionsOfId(next, theRemainingCount);
expungeHistoricalVersionsOfId(theRequestDetails, next, theRemainingCount);
if (theRemainingCount.get() <= 0) {
return;
}
@ -145,21 +173,21 @@ class ResourceExpungeService implements IResourceExpungeService {
@Override
@Transactional
public void expungeHistoricalVersions(List<Long> theHistoricalIds, AtomicInteger theRemainingCount) {
public void expungeHistoricalVersions(RequestDetails theRequestDetails, List<Long> theHistoricalIds, AtomicInteger theRemainingCount) {
for (Long next : theHistoricalIds) {
expungeHistoricalVersion(next);
expungeHistoricalVersion(theRequestDetails, next);
if (theRemainingCount.decrementAndGet() <= 0) {
return;
}
}
}
private void expungeCurrentVersionOfResource(Long myResourceId, AtomicInteger theRemainingCount) {
private void expungeCurrentVersionOfResource(RequestDetails theRequestDetails, Long myResourceId, AtomicInteger theRemainingCount) {
ResourceTable resource = myResourceTableDao.findById(myResourceId).orElseThrow(IllegalStateException::new);
ResourceHistoryTable currentVersion = myResourceHistoryTableDao.findForIdAndVersion(resource.getId(), resource.getVersion());
if (currentVersion != null) {
expungeHistoricalVersion(currentVersion.getId());
expungeHistoricalVersion(theRequestDetails, currentVersion.getId());
}
ourLog.info("Expunging current version of resource {}", resource.getIdDt().getValue());
@ -194,7 +222,7 @@ class ResourceExpungeService implements IResourceExpungeService {
myResourceTagDao.deleteByResourceId(theResourceId);
}
private void expungeHistoricalVersionsOfId(Long myResourceId, AtomicInteger theRemainingCount) {
private void expungeHistoricalVersionsOfId(RequestDetails theRequestDetails, Long myResourceId, AtomicInteger theRemainingCount) {
ResourceTable resource = myResourceTableDao.findById(myResourceId).orElseThrow(IllegalArgumentException::new);
Pageable page = PageRequest.of(0, theRemainingCount.get());
@ -202,7 +230,7 @@ class ResourceExpungeService implements IResourceExpungeService {
Slice<Long> versionIds = myResourceHistoryTableDao.findForResourceId(page, resource.getId(), resource.getVersion());
ourLog.debug("Found {} versions of resource {} to expunge", versionIds.getNumberOfElements(), resource.getIdDt().getValue());
for (Long nextVersionId : versionIds) {
expungeHistoricalVersion(nextVersionId);
expungeHistoricalVersion(theRequestDetails, nextVersionId);
if (theRemainingCount.decrementAndGet() <= 0) {
return;
}

View File

@ -20,238 +20,12 @@ package ca.uhn.fhir.jpa.provider;
* #L%
*/
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.DaoRegistry;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.AttachmentUtil;
import ca.uhn.fhir.util.DateUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import static ca.uhn.fhir.util.UrlUtil.sanitizeUrlPart;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
* This plain provider class can be registered with a JPA RestfulServer
* to provide the <code>$binary-access-read</code> and <code>$binary-access-write</code>
* operations that can be used to access attachment data as a raw binary.
* @deprecated Use ca.uhn.fhir.jpa.binstore.BinaryAccessProvider instead
*/
public class BinaryAccessProvider {
@Autowired
private FhirContext myCtx;
@Autowired
private DaoRegistry myDaoRegistry;
@Autowired(required = false)
private IBinaryStorageSvc myBinaryStorageSvc;
/**
* $binary-access-read
*/
@Operation(name = JpaConstants.OPERATION_BINARY_ACCESS_READ, global = true, manualResponse = true, idempotent = true)
public void binaryAccessRead(
@IdParam IIdType theResourceId,
@OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath,
ServletRequestDetails theRequestDetails,
HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws IOException {
validateResourceTypeAndPath(theResourceId, thePath);
IFhirResourceDao dao = getDaoForRequest(theResourceId);
IBaseResource resource = dao.read(theResourceId, theRequestDetails, false);
ICompositeType attachment = findAttachmentForRequest(resource, thePath, theRequestDetails);
IBaseHasExtensions attachmentHasExt = (IBaseHasExtensions) attachment;
Optional<? extends IBaseExtension<?, ?>> attachmentId = attachmentHasExt
.getExtension()
.stream()
.filter(t -> JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID.equals(t.getUrl()))
.findFirst();
if (attachmentId.isPresent()) {
@SuppressWarnings("unchecked")
IPrimitiveType<String> value = (IPrimitiveType<String>) attachmentId.get().getValue();
String blobId = value.getValueAsString();
IBinaryStorageSvc.StoredDetails blobDetails = myBinaryStorageSvc.fetchBlobDetails(theResourceId, blobId);
if (blobDetails == null) {
String msg = myCtx.getLocalizer().getMessage(BinaryAccessProvider.class, "unknownBlobId");
throw new InvalidRequestException(msg);
}
theServletResponse.setStatus(200);
theServletResponse.setContentType(blobDetails.getContentType());
if (blobDetails.getBytes() <= Integer.MAX_VALUE) {
theServletResponse.setContentLength((int) blobDetails.getBytes());
}
RestfulServer server = theRequestDetails.getServer();
server.addHeadersToResponse(theServletResponse);
theServletResponse.addHeader(Constants.HEADER_CACHE_CONTROL, Constants.CACHE_CONTROL_PRIVATE);
theServletResponse.addHeader(Constants.HEADER_ETAG, '"' + blobDetails.getHash() + '"');
theServletResponse.addHeader(Constants.HEADER_LAST_MODIFIED, DateUtils.formatDate(blobDetails.getPublished()));
myBinaryStorageSvc.writeBlob(theResourceId, blobId, theServletResponse.getOutputStream());
theServletResponse.getOutputStream().close();
myBinaryStorageSvc.writeBlob(theResourceId, blobId, theServletResponse.getOutputStream());
} else {
IPrimitiveType<String> contentTypeDt = AttachmentUtil.getOrCreateContentType(theRequestDetails.getFhirContext(), attachment);
String contentType = contentTypeDt.getValueAsString();
contentType = StringUtils.defaultIfBlank(contentType, Constants.CT_OCTET_STREAM);
IPrimitiveType<byte[]> dataDt = AttachmentUtil.getOrCreateData(theRequestDetails.getFhirContext(), attachment);
byte[] data = dataDt.getValue();
if (data == null) {
String msg = myCtx.getLocalizer().getMessage(BinaryAccessProvider.class, "noAttachmentDataPresent", sanitizeUrlPart(theResourceId), sanitizeUrlPart(thePath));
throw new InvalidRequestException(msg);
}
theServletResponse.setStatus(200);
theServletResponse.setContentType(contentType);
theServletResponse.setContentLength(data.length);
RestfulServer server = theRequestDetails.getServer();
server.addHeadersToResponse(theServletResponse);
theServletResponse.getOutputStream().write(data);
theServletResponse.getOutputStream().close();
}
}
/**
* $binary-access-write
*/
@SuppressWarnings("unchecked")
@Operation(name = JpaConstants.OPERATION_BINARY_ACCESS_WRITE, global = true, manualRequest = true, idempotent = false)
public IBaseResource binaryAccessWrite(
@IdParam IIdType theResourceId,
@OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath,
ServletRequestDetails theRequestDetails,
HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws IOException {
validateResourceTypeAndPath(theResourceId, thePath);
IFhirResourceDao dao = getDaoForRequest(theResourceId);
IBaseResource resource = dao.read(theResourceId, theRequestDetails, false);
ICompositeType attachment = findAttachmentForRequest(resource, thePath, theRequestDetails);
String requestContentType = theServletRequest.getContentType();
if (isBlank(requestContentType)) {
throw new InvalidRequestException("No content-attachment supplied");
}
if (EncodingEnum.forContentTypeStrict(requestContentType) != null) {
throw new InvalidRequestException("This operation is for binary content, got: " + requestContentType);
}
long size = theServletRequest.getContentLength();
String blobId = null;
if (size > 0) {
if (myBinaryStorageSvc != null) {
if (myBinaryStorageSvc.shouldStoreBlob(size, theResourceId, requestContentType)) {
IBinaryStorageSvc.StoredDetails storedDetails = myBinaryStorageSvc.storeBlob(theResourceId, requestContentType, theRequestDetails.getInputStream());
size = storedDetails.getBytes();
blobId = storedDetails.getBlobId();
Validate.notBlank(blobId, "BinaryStorageSvc returned a null blob ID"); // should not happen
}
}
}
if (blobId == null) {
byte[] bytes = IOUtils.toByteArray(theRequestDetails.getInputStream());
size = bytes.length;
AttachmentUtil.setData(theRequestDetails.getFhirContext(), attachment, bytes);
} else {
IBaseHasExtensions attachmentHasExt = (IBaseHasExtensions) attachment;
attachmentHasExt.getExtension().removeIf(t -> JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID.equals(t.getUrl()));
AttachmentUtil.setData(myCtx, attachment, null);
IBaseExtension<?, ?> ext = attachmentHasExt.addExtension();
ext.setUrl(JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID);
IPrimitiveType<String> blobIdString = (IPrimitiveType<String>) myCtx.getElementDefinition("string").newInstance();
blobIdString.setValueAsString(blobId);
ext.setValue(blobIdString);
}
AttachmentUtil.setContentType(theRequestDetails.getFhirContext(), attachment, requestContentType);
AttachmentUtil.setSize(theRequestDetails.getFhirContext(), attachment, null);
if (size <= Integer.MAX_VALUE) {
AttachmentUtil.setSize(theRequestDetails.getFhirContext(), attachment, (int) size);
}
DaoMethodOutcome outcome = dao.update(resource, theRequestDetails);
return outcome.getResource();
}
@Nonnull
private ICompositeType findAttachmentForRequest(IBaseResource theResource, @OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath, ServletRequestDetails theRequestDetails) {
FhirContext ctx = theRequestDetails.getFhirContext();
String path = thePath.getValueAsString();
Optional<ICompositeType> type = ctx.newFluentPath().evaluateFirst(theResource, path, ICompositeType.class);
if (!type.isPresent()) {
throw new InvalidRequestException("Unable to find Attachment at path: " + sanitizeUrlPart(path));
}
BaseRuntimeElementDefinition<?> def = ctx.getElementDefinition(type.get().getClass());
if (!def.getName().equals("Attachment")) {
throw new InvalidRequestException("Path does not return an Attachment: " + sanitizeUrlPart(path));
}
return type.get();
}
private void validateResourceTypeAndPath(@IdParam IIdType theResourceId, @OperationParam(name = "path", min = 1, max = 1) IPrimitiveType<String> thePath) {
if (isBlank(theResourceId.getResourceType())) {
throw new InvalidRequestException("No resource type specified");
}
if (isBlank(theResourceId.getIdPart())) {
throw new InvalidRequestException("No ID specified");
}
if (thePath == null || isBlank(thePath.getValue())) {
throw new InvalidRequestException("No path specified");
}
}
@Nonnull
private IFhirResourceDao getDaoForRequest(@IdParam IIdType theResourceId) {
String resourceType = theResourceId.getResourceType();
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceType);
if (dao == null) {
throw new InvalidRequestException("Unknown/unsupported resource type: " + sanitizeUrlPart(resourceType));
}
return dao;
}
@Deprecated
public class BinaryAccessProvider extends ca.uhn.fhir.jpa.binstore.BinaryAccessProvider {
// FIXME: JA delete before 4.0.0
}

View File

@ -130,6 +130,13 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
return getQueriesForCurrentThreadStartingWith("insert");
}
/**
* Returns all INSERT queries executed on the current thread - Index 0 is oldest
*/
public List<SqlQuery> getAllQueriesForCurrentThread() {
return getQueriesForCurrentThreadStartingWith("");
}
/**
* Returns all UPDATE queries executed on the current thread - Index 0 is oldest
*/
@ -209,6 +216,17 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
ourLog.info("Insert Queries:\n{}", String.join("\n", queries));
}
/**
* Log all captured INSERT queries
*/
public void logAllQueriesForCurrentThread() {
List<String> queries = getAllQueriesForCurrentThread()
.stream()
.map(CircularQueueCaptureQueriesListener::formatQueryAsSql)
.collect(Collectors.toList());
ourLog.info("Insert Queries:\n{}", String.join("\n", queries));
}
/**
* Log all captured INSERT queries
*/

View File

@ -0,0 +1,133 @@
package ca.uhn.fhir.jpa.binstore;
import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import org.hl7.fhir.r4.model.IdType;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
@ContextConfiguration(classes = DatabaseBlobBinaryStorageSvcImplTest.MyConfig.class)
public class DatabaseBlobBinaryStorageSvcImplTest extends BaseJpaR4Test {
private static final byte[] SOME_BYTES = {2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1};
@Autowired
@Qualifier("databaseBlobBinaryStorageSvc")
private IBinaryStorageSvc mySvc;
@Test
public void testStoreAndRetrieve() throws IOException {
myCaptureQueriesListener.clear();
/*
* Store the binary
*/
ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES);
String contentType = "image/png";
IdType resourceId = new IdType("Binary/123");
IBinaryStorageSvc.StoredDetails outcome = mySvc.storeBlob(resourceId, contentType, inputStream);
myCaptureQueriesListener.logAllQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
assertEquals(1, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
assertEquals(2, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
myCaptureQueriesListener.clear();
assertThat(outcome.getBlobId(), matchesPattern("^[a-zA-Z0-9]{100}$"));
assertEquals(16, outcome.getBytes());
/*
* Read back the details
*/
IBinaryStorageSvc.StoredDetails details = mySvc.fetchBlobDetails(resourceId, outcome.getBlobId());
assertEquals(16L, details.getBytes());
assertEquals(outcome.getBlobId(), details.getBlobId());
assertEquals("image/png", details.getContentType());
assertEquals("dc7197cfab936698bef7818975c185a9b88b71a0a0a2493deea487706ddf20cb", details.getHash());
assertNotNull(details.getPublished());
/*
* Read back the contents
*/
ByteArrayOutputStream capture = new ByteArrayOutputStream();
mySvc.writeBlob(resourceId, outcome.getBlobId(), capture);
assertArrayEquals(SOME_BYTES, capture.toByteArray());
}
@Test
public void testExpunge() throws IOException {
/*
* Store the binary
*/
ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES);
String contentType = "image/png";
IdType resourceId = new IdType("Binary/123");
IBinaryStorageSvc.StoredDetails outcome = mySvc.storeBlob(resourceId, contentType, inputStream);
String blobId = outcome.getBlobId();
// Expunge
mySvc.expungeBlob(resourceId, blobId);
ByteArrayOutputStream capture = new ByteArrayOutputStream();
assertFalse(mySvc.writeBlob(resourceId, outcome.getBlobId(), capture));
assertEquals(0, capture.size());
}
@Test
public void testWrongResourceId() throws IOException {
/*
* Store the binary
*/
ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES);
String contentType = "image/png";
IdType resourceId = new IdType("Binary/123");
IBinaryStorageSvc.StoredDetails outcome = mySvc.storeBlob(resourceId, contentType, inputStream);
// Right ID
ByteArrayOutputStream capture = new ByteArrayOutputStream();
assertTrue(mySvc.writeBlob(resourceId, outcome.getBlobId(), capture));
assertEquals(16, capture.size());
// Wrong ID
capture = new ByteArrayOutputStream();
assertFalse(mySvc.writeBlob(new IdType("Patient/9999"), outcome.getBlobId(), capture));
assertEquals(0, capture.size());
}
@Configuration
public static class MyConfig {
@Primary
@Bean
public IBinaryStorageSvc databaseBlobBinaryStorageSvc() {
return new DatabaseBlobBinaryStorageSvcImpl();
}
}
}

View File

@ -18,8 +18,8 @@ import static org.junit.Assert.*;
public class FilesystemBinaryStorageSvcImplTest {
private static final Logger ourLog = LoggerFactory.getLogger(FilesystemBinaryStorageSvcImplTest.class);
public static final byte[] SOME_BYTES = {2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1};
private static final Logger ourLog = LoggerFactory.getLogger(FilesystemBinaryStorageSvcImplTest.class);
private File myPath;
private FilesystemBinaryStorageSvcImpl mySvc;
@ -56,4 +56,26 @@ public class FilesystemBinaryStorageSvcImplTest {
}
@Test
public void testExpunge() throws IOException {
IIdType id = new IdType("Patient/123");
String contentType = "image/png";
IBinaryStorageSvc.StoredDetails outcome = mySvc.storeBlob(id, contentType, new ByteArrayInputStream(SOME_BYTES));
ourLog.info("Got id: {}", outcome);
IBinaryStorageSvc.StoredDetails details = mySvc.fetchBlobDetails(id, outcome.getBlobId());
assertEquals(16L, details.getBytes());
assertEquals(outcome.getBlobId(), details.getBlobId());
assertEquals("image/png", details.getContentType());
assertEquals("dc7197cfab936698bef7818975c185a9b88b71a0a0a2493deea487706ddf20cb", details.getHash());
assertNotNull(details.getPublished());
mySvc.expungeBlob(id, outcome.getBlobId());
ByteArrayOutputStream capture = new ByteArrayOutputStream();
mySvc.writeBlob(id, outcome.getBlobId(), capture);
assertEquals(0, capture.size());
}
}

View File

@ -28,4 +28,10 @@ public class NullBinaryStorageSvcImplTest {
public void writeBlob() {
mySvc.writeBlob(null, null, null);
}
@Test(expected = UnsupportedOperationException.class)
public void expungeBlob() {
mySvc.expungeBlob(null, null);
}
}

View File

@ -10,10 +10,12 @@ import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.dialect.H2Dialect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@ -42,6 +44,9 @@ public class TestR4Config extends BaseJavaConfigR4 {
}
}
@Autowired
private Environment myEnvironment;
private Exception myLastStackTrace;
@Bean
@ -93,6 +98,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
}
};
retVal.setDriver(new org.h2.Driver());
retVal.setUrl("jdbc:h2:mem:testdb_r4");
retVal.setMaxWaitMillis(10000);

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.dao.data.*;
@ -10,7 +11,7 @@ import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.provider.BinaryAccessProvider;
import ca.uhn.fhir.jpa.binstore.BinaryAccessProvider;
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
@ -55,6 +56,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.util.AopTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
@ -98,6 +100,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Autowired
protected BinaryAccessProvider myBinaryAccessProvider;
@Autowired
protected BinaryStorageInterceptor myBinaryStorageInterceptor;
@Autowired
protected ApplicationContext myAppCtx;
@Autowired
@Qualifier("myAppointmentDaoR4")

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -249,7 +250,9 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
assertEquals("Patient/PT00000", ids.get(0));
assertEquals("Patient/PT00009", ids.get(9));
assertEquals(200, myDatabaseBackedPagingProvider.retrieveResultList(null, uuid2).size().intValue());
IBundleProvider results2 = myDatabaseBackedPagingProvider.retrieveResultList(null, uuid2);
Integer results2Size = results2.size();
assertEquals(200, results2Size.intValue());
assertNotEquals(uuid, uuid2);
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.config.TestR4WithoutLuceneConfig;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
@ -25,6 +26,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;

View File

@ -100,6 +100,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
ourRestServer = new RestfulServer(myFhirCtx);
ourRestServer.registerProviders(myResourceProviders.createProviders());
ourRestServer.registerProvider(myBinaryAccessProvider);
ourRestServer.getInterceptorService().registerInterceptor(myBinaryStorageInterceptor);
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
ourRestServer.setDefaultResponseEncoding(EncodingEnum.XML);

View File

@ -4,8 +4,10 @@ import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.binstore.MemoryBinaryStorageSvcImpl;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -14,9 +16,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.DocumentReference;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -24,6 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.hamcrest.Matchers.containsString;
@ -44,14 +45,17 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
@Before
public void before() throws Exception {
super.before();
myStorageSvc.setMinSize(10);
myStorageSvc.setMinimumBinarySize(10);
myDaoConfig.setExpungeEnabled(true);
myInterceptorRegistry.registerInterceptor(myBinaryStorageInterceptor);
}
@Override
@After
public void after() throws Exception {
super.after();
myStorageSvc.setMinSize(0);
myStorageSvc.setMinimumBinarySize(0);
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
}
@Test
@ -163,7 +167,8 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
DocumentReference dr = ourClient.read().resource(DocumentReference.class).withId(id).execute();
dr.getContentFirstRep()
.getAttachment()
.addExtension(JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID, new StringType("AAAAA"));
.getDataElement()
.addExtension(JpaConstants.EXT_EXTERNALIZED_BINARY_ID, new StringType("AAAAA"));
ourClient.update().resource(dr).execute();
String path = ourServerBase +
@ -185,7 +190,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
* Stores a binary large enough that it should live in binary storage
*/
@Test
public void testWriteLarge() throws IOException {
public void testWriteLargeAttachment() throws IOException {
IIdType id = createDocumentReference(false);
IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
@ -217,7 +222,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
assertEquals(15, attachment.getSize());
assertEquals(null, attachment.getData());
assertEquals("2", ref.getMeta().getVersionId());
attachmentId = attachment.getExtensionString(JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID);
attachmentId = attachment.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
}
@ -249,7 +254,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
* Stores a binary small enough that it shouldn't live in binary storage
*/
@Test
public void testWriteSmall() throws IOException {
public void testWriteSmallAttachment() throws IOException {
IIdType id = createDocumentReference(false);
IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
@ -281,7 +286,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
assertEquals(4, attachment.getSize());
assertArrayEquals(SOME_BYTES_2, attachment.getData());
assertEquals("2", ref.getMeta().getVersionId());
attachmentId = attachment.getExtensionString(JpaConstants.EXT_ATTACHMENT_EXTERNAL_BINARY_ID);
attachmentId = attachment.getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
assertEquals(null, attachmentId);
}
@ -292,6 +297,129 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
}
/**
* Stores a binary large enough that it should live in binary storage
*/
@Test
public void testWriteLargeBinary() throws IOException {
Binary binary = new Binary();
binary.setContentType("image/png");
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(binary));
IIdType id = ourClient.create().resource(binary).execute().getId().toUnqualifiedVersionless();
IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESHOW_RESOURCES, interceptor);
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, interceptor);
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, interceptor);
// Write using the operation
String path = ourServerBase +
"/Binary/" + id.getIdPart() + "/" +
JpaConstants.OPERATION_BINARY_ACCESS_WRITE +
"?path=Binary";
HttpPost post = new HttpPost(path);
post.setEntity(new ByteArrayEntity(SOME_BYTES, ContentType.IMAGE_JPEG));
post.addHeader("Accept", "application/fhir+json; _pretty=true");
String attachmentId;
try (CloseableHttpResponse resp = ourHttpClient.execute(post)) {
assertEquals(200, resp.getStatusLine().getStatusCode());
assertThat(resp.getEntity().getContentType().getValue(), containsString("application/fhir+json"));
String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
ourLog.info("Response: {}", response);
Binary target = myFhirCtx.newJsonParser().parseResource(Binary.class, response);
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
assertEquals(null, target.getData());
assertEquals("2", target.getMeta().getVersionId());
attachmentId = target.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
}
verify(interceptor, timeout(5000).times(1)).invoke(eq(Pointcut.STORAGE_PRESHOW_RESOURCES), any());
verify(interceptor, timeout(5000).times(1)).invoke(eq(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED), any());
verifyNoMoreInteractions(interceptor);
// Read it back using the operation
path = ourServerBase +
"/Binary/" + id.getIdPart() + "/" +
JpaConstants.OPERATION_BINARY_ACCESS_READ +
"?path=Binary";
HttpGet get = new HttpGet(path);
try (CloseableHttpResponse resp = ourHttpClient.execute(get)) {
assertEquals(200, resp.getStatusLine().getStatusCode());
assertEquals("image/jpeg", resp.getEntity().getContentType().getValue());
assertEquals(SOME_BYTES.length, resp.getEntity().getContentLength());
byte[] actualBytes = IOUtils.toByteArray(resp.getEntity().getContent());
assertArrayEquals(SOME_BYTES, actualBytes);
}
}
/**
* Stores a binary large enough that it should live in binary storage
*/
@Test
public void testWriteLargeBinaryWithoutExplicitPath() throws IOException {
Binary binary = new Binary();
binary.setContentType("image/png");
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(binary));
IIdType id = ourClient.create().resource(binary).execute().getId().toUnqualifiedVersionless();
// Write using the operation
String path = ourServerBase +
"/Binary/" + id.getIdPart() + "/" +
JpaConstants.OPERATION_BINARY_ACCESS_WRITE;
HttpPost post = new HttpPost(path);
post.setEntity(new ByteArrayEntity(SOME_BYTES, ContentType.IMAGE_JPEG));
post.addHeader("Accept", "application/fhir+json; _pretty=true");
String attachmentId;
try (CloseableHttpResponse resp = ourHttpClient.execute(post)) {
assertEquals(200, resp.getStatusLine().getStatusCode());
assertThat(resp.getEntity().getContentType().getValue(), containsString("application/fhir+json"));
String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
ourLog.info("Response: {}", response);
Binary target = myFhirCtx.newJsonParser().parseResource(Binary.class, response);
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
assertEquals(null, target.getData());
assertEquals("2", target.getMeta().getVersionId());
attachmentId = target.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
}
// Read it back using the operation
path = ourServerBase +
"/Binary/" + id.getIdPart() + "/" +
JpaConstants.OPERATION_BINARY_ACCESS_READ;
HttpGet get = new HttpGet(path);
try (CloseableHttpResponse resp = ourHttpClient.execute(get)) {
assertEquals(200, resp.getStatusLine().getStatusCode());
assertEquals("image/jpeg", resp.getEntity().getContentType().getValue());
assertEquals(SOME_BYTES.length, resp.getEntity().getContentLength());
byte[] actualBytes = IOUtils.toByteArray(resp.getEntity().getContent());
assertArrayEquals(SOME_BYTES, actualBytes);
}
}
private IIdType createDocumentReference(boolean theSetData) {
DocumentReference documentReference = new DocumentReference();
Attachment attachment = documentReference
@ -315,6 +443,60 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
}
@Test
public void testResourceExpungeAlsoExpungesBinaryData() throws IOException {
IIdType id = createDocumentReference(false);
String path = ourServerBase +
"/DocumentReference/" + id.getIdPart() + "/" +
JpaConstants.OPERATION_BINARY_ACCESS_WRITE +
"?path=DocumentReference.content.attachment";
HttpPost post = new HttpPost(path);
post.setEntity(new ByteArrayEntity(SOME_BYTES, ContentType.IMAGE_JPEG));
post.addHeader("Accept", "application/fhir+json; _pretty=true");
String attachmentId;
try (CloseableHttpResponse resp = ourHttpClient.execute(post)) {
assertEquals(200, resp.getStatusLine().getStatusCode());
assertThat(resp.getEntity().getContentType().getValue(), containsString("application/fhir+json"));
String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
DocumentReference ref = myFhirCtx.newJsonParser().parseResource(DocumentReference.class, response);
Attachment attachment = ref.getContentFirstRep().getAttachment();
attachmentId = attachment.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
}
ByteArrayOutputStream capture = new ByteArrayOutputStream();
myStorageSvc.writeBlob(id, attachmentId, capture);
assertEquals(15, capture.size());
// Now delete (logical delete- should not expunge the binary)
ourClient.delete().resourceById(id).execute();
try {
ourClient.read().resource("DocumentReference").withId(id).execute();
fail();
} catch (ResourceGoneException e) {
// good
}
capture = new ByteArrayOutputStream();
myStorageSvc.writeBlob(id, attachmentId, capture);
assertEquals(15, capture.size());
// Now expunge
Parameters parameters = new Parameters();
parameters.addParameter().setName(JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES).setValue(new BooleanType(true));
ourClient
.operation()
.onInstance(id)
.named(JpaConstants.OPERATION_EXPUNGE)
.withParameters(parameters)
.execute();
capture = new ByteArrayOutputStream();
assertFalse(myStorageSvc.writeBlob(id, attachmentId, capture));
assertEquals(0, capture.size());
}
}

View File

@ -339,12 +339,18 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
public void testExpungeEverythingWhereResourceInSearchResults() {
createStandardPatients();
IBundleProvider search = myPatientDao.search(new SearchParameterMap());
runInTransaction(() -> {
await().until(()->mySearchEntityDao.count() == 0);
await().until(()->mySearchResultDao.count() == 0);
});
PersistedJpaSearchFirstPageBundleProvider search = (PersistedJpaSearchFirstPageBundleProvider) myPatientDao.search(new SearchParameterMap());
assertEquals(PersistedJpaSearchFirstPageBundleProvider.class, search.getClass());
assertEquals(2, search.size().intValue());
assertEquals(2, search.getResources(0, 2).size());
runInTransaction(() -> {
await().until(()->mySearchEntityDao.count() == 1);
await().until(()->mySearchResultDao.count() == 2);
ourLog.info("Search results: {}", mySearchResultDao.findAll().toString());
assertEquals(mySearchResultDao.findAll().toString(), 2, mySearchResultDao.count());

View File

@ -157,6 +157,8 @@ public class JdbcUtils {
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
return BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP.getDescriptor(null);
case Types.BLOB:
return BaseTableColumnTypeTask.ColumnTypeEnum.BLOB.getDescriptor(null);
default:
throw new IllegalArgumentException("Don't know how to handle datatype " + dataType + " for column " + theColumnName + " on table " + theTableName);
}

View File

@ -86,6 +86,15 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
setColumnType(ColumnTypeEnum.BOOLEAN, DriverTypeEnum.ORACLE_12C, "number(1,0)");
setColumnType(ColumnTypeEnum.BOOLEAN, DriverTypeEnum.POSTGRES_9_4, "boolean");
setColumnType(ColumnTypeEnum.BOOLEAN, DriverTypeEnum.MYSQL_5_7, "bit");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.H2_EMBEDDED, "blob");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.DERBY_EMBEDDED, "blob");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.MARIADB_10_1, "longblob");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.MYSQL_5_7, "longblob");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.ORACLE_12C, "blob");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.POSTGRES_9_4, "oid");
setColumnType(ColumnTypeEnum.BLOB, DriverTypeEnum.MSSQL_2012, "varbinary(MAX)");
}
public ColumnTypeEnum getColumnType() {
@ -197,6 +206,14 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
return "int";
}
},
BLOB {
@Override
public String getDescriptor(Long theColumnLength) {
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
return "blob";
}
};

View File

@ -63,6 +63,16 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
protected void init400() {
Builder version = forVersion(VersionEnum.V4_0_0);
// BinaryStorageEntity
Builder.BuilderAddTableByColumns binaryBlob = version.addTableByColumns("HFJ_BINARY_STORAGE_BLOB", "BLOB_ID");
binaryBlob.addColumn("BLOB_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 200);
binaryBlob.addColumn("RESOURCE_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 100);
binaryBlob.addColumn("BLOB_SIZE").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
binaryBlob.addColumn("CONTENT_TYPE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 100);
binaryBlob.addColumn("BLOB_DATA").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.BLOB);
binaryBlob.addColumn("PUBLISHED_DATE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
binaryBlob.addColumn("BLOB_HASH").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 128);
// Interim builds used this name
version.onTable("TRM_VALUESET_CODE").dropThisTable();

View File

@ -0,0 +1,87 @@
package ca.uhn.fhir.jpa.model.entity;
import javax.persistence.*;
import java.sql.Blob;
import java.util.Date;
@Entity
@Table(name = "HFJ_BINARY_STORAGE_BLOB")
public class BinaryStorageEntity {
@Id
@Column(name = "BLOB_ID", length = 200, nullable = false)
private String myBlobId;
@Column(name = "RESOURCE_ID", length = 100, nullable = false)
private String myResourceId;
@Column(name = "BLOB_SIZE", nullable = true)
private int mySize;
@Column(name = "CONTENT_TYPE", nullable = false, length = 100)
private String myBlobContentType;
@Lob
@Column(name = "BLOB_DATA", nullable = false, insertable = true, updatable = false)
private Blob myBlob;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "PUBLISHED_DATE", nullable = false)
private Date myPublished;
@Column(name = "BLOB_HASH", length = 128, nullable = true)
private String myHash;
public Date getPublished() {
if (myPublished == null) {
return null;
}
return new Date(myPublished.getTime());
}
public void setPublished(Date thePublishedDate) {
myPublished = thePublishedDate;
}
public String getHash() {
return myHash;
}
public void setHash(String theHash) {
myHash = theHash;
}
public String getBlobId() {
return myBlobId;
}
public void setBlobId(String theBlobId) {
myBlobId = theBlobId;
}
public String getResourceId() {
return myResourceId;
}
public void setResourceId(String theResourceId) {
myResourceId = theResourceId;
}
public int getSize() {
return mySize;
}
public void setSize(int theSize) {
mySize = theSize;
}
public String getBlobContentType() {
return myBlobContentType;
}
public void setBlobContentType(String theBlobContentType) {
myBlobContentType = theBlobContentType;
}
public Blob getBlob() {
return myBlob;
}
public void setBlob(Blob theBlob) {
myBlob = theBlob;
}
}

View File

@ -210,6 +210,6 @@ public class JpaConstants {
/**
* Extension ID for external binary references
*/
public static final String EXT_ATTACHMENT_EXTERNAL_BINARY_ID = "http://hapifhir.io/fhir/StructureDefinition/attachment-external-binary-id";
public static final String EXT_EXTERNALIZED_BINARY_ID = "http://hapifhir.io/fhir/StructureDefinition/externalized-binary-id";
}

View File

@ -418,9 +418,9 @@ public class GenericClientDstu2_1Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/xml+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals("application/json+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_JSON, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals(Constants.CT_FHIR_JSON, output.getContentType());
Patient outputPt = (Patient) ourCtx.newJsonParser().parseResource(new String(output.getContent(), "UTF-8"));
@ -457,9 +457,9 @@ public class GenericClientDstu2_1Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/xml+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
assertEquals("application/json+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_JSON, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
}
@ -569,7 +569,7 @@ public class GenericClientDstu2_1Test {
assertEquals(myAnswerCount, capt.getAllValues().size());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals(Constants.CT_FHIR_JSON, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("http://foo.com/base/Patient/222/_history/3", capt.getAllValues().get(1).getURI().toASCIIString());
}
@ -1076,6 +1076,7 @@ public class GenericClientDstu2_1Test {
.update()
.resource(bundle)
.prefer(PreferReturnEnum.REPRESENTATION)
.encodedXml()
.execute();
HttpPut httpRequest = (HttpPut) capt.getValue();
@ -1670,10 +1671,10 @@ public class GenericClientDstu2_1Test {
assertEquals("http://example.com/fhir/Patient/111", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/xml+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertEquals("application/json+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.CT_FHIR_JSON, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
String body = extractBodyAsString(capt);
assertThat(body, containsString("<id value=\"111\"/>"));
assertThat(body, containsString("\"id\":\"111\""));
}
@Test

View File

@ -144,7 +144,7 @@ public class NonGenericClientDstu2_1Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
String request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":[\"FAM\"]}]}}]}", request);
idx = 1;
outcome = client.validate(patient, ValidationModeEnum.CREATE, "http://foo");
@ -152,7 +152,7 @@ public class NonGenericClientDstu2_1Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter><parameter><name value=\"mode\"/><valueString value=\"create\"/></parameter><parameter><name value=\"profile\"/><valueString value=\"http://foo\"/></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":[\"FAM\"]}]}},{\"name\":\"mode\",\"valueString\":\"create\"},{\"name\":\"profile\",\"valueString\":\"http://foo\"}]}", request);
}

View File

@ -96,7 +96,7 @@ public class OperationClientDstu2_1Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());
@ -131,7 +131,7 @@ public class OperationClientDstu2_1Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());

View File

@ -74,7 +74,7 @@ public class BundleTypeDstu2Test {
p1.addIdentifier().setSystem("urn:system").setValue("value");
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
client.transaction().withResources(Arrays.asList((IBaseResource) p1)).execute();
client.transaction().withResources(Arrays.asList((IBaseResource) p1)).encodedXml().execute();
HttpUriRequest value = capt.getValue();

View File

@ -79,7 +79,7 @@ public class ClientWithProfileDstu2Test {
int idx = 0;
client.create().resource(new MyPatient()).execute();
client.create().resource(new MyPatient()).encodedXml().execute();
HttpPost value = (HttpPost) capt.getAllValues().get(idx);
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());

View File

@ -296,7 +296,7 @@ public class GenericClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
@ -307,7 +307,7 @@ public class GenericClientDstu2Test {
p.setId("123");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
String body = extractBody(capt, idx);
@ -338,7 +338,7 @@ public class GenericClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.create().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -347,7 +347,7 @@ public class GenericClientDstu2Test {
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -356,7 +356,7 @@ public class GenericClientDstu2Test {
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).execute();
client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -387,7 +387,7 @@ public class GenericClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create().resource(p).execute();
client.create().resource(p).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
@ -767,6 +767,7 @@ public class GenericClientDstu2Test {
.add()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$meta-add", capt.getAllValues().get(idx).getURI().toASCIIString());
@ -1072,13 +1073,13 @@ public class GenericClientDstu2Test {
int idx = 0;
//@formatter:off
Parameters resp = client
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
//@formatter:on
.withParameters(inParams)
.encodedXml()
.execute();
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
@ -1113,15 +1114,14 @@ public class GenericClientDstu2Test {
int idx = 0;
//@formatter:off
Parameters resp = client
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameter(Parameters.class, "name1", new StringDt("value1"))
.andParameter("name2", new StringDt("value1"))
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
@ -1148,10 +1148,10 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueIdentifier><system value=\"system1\"/><value value=\"value1\"/></valueIdentifier></parameter><parameter><name value=\"name2\"/><valueString value=\"value1\"/></parameter></Parameters>",
"{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"name1\",\"valueIdentifier\":{\"system\":\"system1\",\"value\":\"value1\"}},{\"name\":\"name2\",\"valueString\":\"value1\"}]}",
(extractBody(capt, idx)));
idx++;
@ -1171,10 +1171,10 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueIdentifier><system value=\"system1\"/><value value=\"value1\"/></valueIdentifier></parameter><parameter><name value=\"name2\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><active value=\"true\"/></Patient></resource></parameter></Parameters>",
"{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"name1\",\"valueIdentifier\":{\"system\":\"system1\",\"value\":\"value1\"}},{\"name\":\"name2\",\"resource\":{\"resourceType\":\"Patient\",\"active\":true}}]}",
(extractBody(capt, idx)));
idx++;
@ -1253,7 +1253,9 @@ public class GenericClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1268,7 +1270,9 @@ public class GenericClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1283,7 +1287,9 @@ public class GenericClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
.withParameters(inParams)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1331,7 +1337,9 @@ public class GenericClientDstu2Test {
.operation()
.onServer()
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1346,7 +1354,9 @@ public class GenericClientDstu2Test {
.operation()
.onType(Patient.class)
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1361,7 +1371,9 @@ public class GenericClientDstu2Test {
.operation()
.onInstance(new IdDt("Patient", "123"))
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class).execute();
.withNoParameters(Parameters.class)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
@ -1377,6 +1389,7 @@ public class GenericClientDstu2Test {
.onInstance(new IdDt("http://foo.com/bar/baz/Patient/123/_history/22"))
.named("$SOMEOPERATION")
.withNoParameters(Parameters.class)
.encodedXml()
.execute();
// @formatter:on
assertEquals("http://example.com/fhir/Patient/123/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
@ -1428,6 +1441,7 @@ public class GenericClientDstu2Test {
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeDt("8495-4"))
.andParameter("system", new UriDt("http://loinc.org"))
.encodedXml()
.execute();
//@formatter:off
@ -2353,7 +2367,7 @@ public class GenericClientDstu2Test {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -2361,7 +2375,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute();
client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -2369,7 +2383,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient?name=http%3A//foo%7Cbar", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -2377,7 +2391,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute();
client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -2385,7 +2399,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient?name=foo&address=AAA%5C%7CBBB", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -2416,16 +2430,16 @@ public class GenericClientDstu2Test {
client.update(new IdDt("Patient/123"), p);
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("{\"family\":[\"FOOFAMILY\"]}"));
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
assertEquals("PUT", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
client.update("123", p);
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("{\"family\":[\"FOOFAMILY\"]}"));
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
assertEquals("PUT", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -2517,7 +2531,7 @@ public class GenericClientDstu2Test {
int idx = 0;
MethodOutcome response;
response = client.validate().resource(p).execute();
response = client.validate().resource(p).encodedXml().execute();
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("application/xml+fhir", capt.getAllValues().get(idx).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
@ -2528,7 +2542,7 @@ public class GenericClientDstu2Test {
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute();
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).encodedXml().execute();
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("application/xml+fhir", capt.getAllValues().get(idx).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
@ -2584,14 +2598,12 @@ public class GenericClientDstu2Test {
int idx = 0;
MethodOutcome response;
//@formatter:off
response = client.validate(p);
//@formatter:on
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
"{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"given\":[\"GIVEN\"]}]}}]}",
extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());

View File

@ -88,7 +88,7 @@ public class OperationClientDstu2Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/Patient/222/$OP_INSTANCE", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());
@ -128,7 +128,7 @@ public class OperationClientDstu2Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/Patient/222/$OP_INSTANCE_WITH_BUNDLE_RETURN", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());
@ -165,7 +165,7 @@ public class OperationClientDstu2Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());
@ -180,7 +180,7 @@ public class OperationClientDstu2Test {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals(1, request.getParameter().size());
assertEquals("PARAM2", request.getParameter().get(0).getName());
assertEquals(Boolean.TRUE, ((Patient) request.getParameter().get(0).getResource()).getActive());
@ -192,7 +192,7 @@ public class OperationClientDstu2Test {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals(0, request.getParameter().size());
idx++;
@ -225,7 +225,7 @@ public class OperationClientDstu2Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(3, request.getParameter().size());
assertEquals("PARAM2", request.getParameter().get(0).getName());
@ -242,7 +242,7 @@ public class OperationClientDstu2Test {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM3", request.getParameter().get(0).getName());
@ -251,13 +251,13 @@ public class OperationClientDstu2Test {
assertEquals("PARAM3str2", ((StringDt) request.getParameter().get(1).getValue()).getValue());
idx++;
response = client.opServerListParam(null, new ArrayList<StringDt>());
response = client.opServerListParam(null, new ArrayList<>());
assertEquals("FOO", response.getParameter().get(0).getName());
value = (HttpPost) capt.getAllValues().get(idx);
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
requestBody = IOUtils.toString(value.getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(0, request.getParameter().size());
idx++;
@ -268,7 +268,7 @@ public class OperationClientDstu2Test {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(0, request.getParameter().size());
idx++;
@ -302,7 +302,7 @@ public class OperationClientDstu2Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/Patient/$OP_TYPE", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());

View File

@ -59,7 +59,7 @@ public class ClientMimetypeDstu3Test {
Patient pt = new Patient();
pt.getText().setDivAsString("A PATIENT");
MethodOutcome outcome = client.create().resource(pt).execute();
MethodOutcome outcome = client.create().resource(pt).encodedXml().execute();
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
@ -79,7 +79,7 @@ public class ClientMimetypeDstu3Test {
Patient pt = new Patient();
pt.getText().setDivAsString("A PATIENT");
MethodOutcome outcome = client.create().resource(pt).execute();
MethodOutcome outcome = client.create().resource(pt).encodedXml().execute();
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());

View File

@ -404,9 +404,9 @@ public class GenericClientDstu3Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals(Constants.CT_FHIR_JSON, output.getContentType());
Patient outputPt = (Patient) ourCtx.newJsonParser().parseResource(new String(output.getContent(), "UTF-8"));
@ -443,9 +443,9 @@ public class GenericClientDstu3Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
}
@ -555,7 +555,7 @@ public class GenericClientDstu3Test {
assertEquals(myAnswerCount, capt.getAllValues().size());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(Constants.CT_FHIR_XML_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals(Constants.CT_FHIR_JSON_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("http://foo.com/base/Patient/222/_history/3", capt.getAllValues().get(1).getURI().toASCIIString());
}
@ -1011,6 +1011,7 @@ public class GenericClientDstu3Test {
.update()
.resource(bundle)
.prefer(PreferReturnEnum.REPRESENTATION)
.encodedXml()
.execute();
HttpPut httpRequest = (HttpPut) capt.getValue();
@ -1635,10 +1636,10 @@ public class GenericClientDstu3Test {
assertEquals("http://example.com/fhir/Patient/111", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
String body = extractBodyAsString(capt);
assertThat(body, containsString("<id value=\"111\"/>"));
assertThat(body, containsString("\"id\":\"111\""));
}
@Test

View File

@ -144,7 +144,7 @@ public class NonGenericClientDstu3Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
String request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"FAM\"}]}}]}", request);
idx = 1;
outcome = client.validate(patient, ValidationModeEnum.CREATE, "http://foo");
@ -152,7 +152,7 @@ public class NonGenericClientDstu3Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter><parameter><name value=\"mode\"/><valueString value=\"create\"/></parameter><parameter><name value=\"profile\"/><valueString value=\"http://foo\"/></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"FAM\"}]}},{\"name\":\"mode\",\"valueString\":\"create\"},{\"name\":\"profile\",\"valueString\":\"http://foo\"}]}", request);
}

View File

@ -96,7 +96,7 @@ public class OperationClientDstu3Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());
@ -131,7 +131,7 @@ public class OperationClientDstu3Test {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());

View File

@ -236,7 +236,7 @@ public class GenericClientDstu2Hl7OrgTest {
@Test
public void testOperationWithListOfParameterResponse() throws Exception {
IParser p = ourCtx.newXmlParser();
IParser p = ourCtx.newJsonParser();
Parameters inParams = new Parameters();
inParams.addParameter().setValue(new StringType("STRINGVALIN1"));
@ -251,7 +251,7 @@ public class GenericClientDstu2Hl7OrgTest {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
@ -263,17 +263,16 @@ public class GenericClientDstu2Hl7OrgTest {
int idx = 0;
//@formatter:off
Parameters resp = client
.operation()
.onServer()
.named("$SOMEOPERATION")
.withParameters(inParams).execute();
//@formatter:on
.withParameters(inParams)
.execute();
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -288,7 +287,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -303,7 +302,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient/123/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -316,7 +315,7 @@ public class GenericClientDstu2Hl7OrgTest {
@Test
public void testOperationWithNoInParameters() throws Exception {
IParser p = ourCtx.newXmlParser();
IParser p = ourCtx.newJsonParser();
Parameters inParams = new Parameters();
final String reqString = p.encodeResourceToString(inParams);
@ -329,7 +328,7 @@ public class GenericClientDstu2Hl7OrgTest {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
@ -351,7 +350,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -366,7 +365,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -381,7 +380,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient/123/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(respString, p.encodeResourceToString(resp));
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
@ -563,7 +562,7 @@ public class GenericClientDstu2Hl7OrgTest {
@Test
public void testOperationWithBundleResponse() throws Exception {
IParser p = ourCtx.newXmlParser();
IParser p = ourCtx.newJsonParser();
Parameters inParams = new Parameters();
inParams.addParameter().setValue(new StringType("STRINGVALIN1"));
@ -577,7 +576,7 @@ public class GenericClientDstu2Hl7OrgTest {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
@ -598,7 +597,7 @@ public class GenericClientDstu2Hl7OrgTest {
//@formatter:on
assertEquals("http://example.com/fhir/$SOMEOPERATION", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(extractBody(capt, idx), reqString);
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(1, resp.getParameter().size());
@ -756,8 +755,8 @@ public class GenericClientDstu2Hl7OrgTest {
client.create().resource(p).conditionalByUrl("Patient?name=foo").execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("{\"family\":[\"FOOFAMILY\"]}"));
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(idx).getURI().toString());
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_IF_NONE_EXIST).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
@ -765,8 +764,8 @@ public class GenericClientDstu2Hl7OrgTest {
client.create().resource(p).conditional().where(new StringClientParam("name").matches().value("foo")).execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("{\"family\":[\"FOOFAMILY\"]}"));
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(idx).getURI().toString());
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_IF_NONE_EXIST).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
@ -793,7 +792,7 @@ public class GenericClientDstu2Hl7OrgTest {
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.update().resource(p).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(p).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -801,7 +800,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -809,7 +808,7 @@ public class GenericClientDstu2Hl7OrgTest {
assertEquals("http://example.com/fhir/Patient?name=foo", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.update().resource(p).conditional().where(new StringClientParam("name").matches().value("foo")).and(new StringClientParam("address").matches().value("AAA|BBB")).execute();
client.update().resource(p).conditional().where(new StringClientParam("name").matches().value("foo")).and(new StringClientParam("address").matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
@ -818,7 +817,7 @@ public class GenericClientDstu2Hl7OrgTest {
idx++;
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(new StringClientParam("name").matches().value("foo"))
.and(new StringClientParam("address").matches().value("AAA|BBB")).execute();
.and(new StringClientParam("address").matches().value("AAA|BBB")).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));

View File

@ -78,7 +78,7 @@ public class OperationClientTest {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/Patient/222/$OP_INSTANCE", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());
@ -115,7 +115,7 @@ public class OperationClientTest {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());
@ -130,7 +130,7 @@ public class OperationClientTest {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals(1, request.getParameter().size());
assertEquals("PARAM2", request.getParameter().get(0).getName());
assertEquals(Boolean.TRUE, ((Patient) request.getParameter().get(0).getResource()).getActive());
@ -142,7 +142,7 @@ public class OperationClientTest {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals(0, request.getParameter().size());
idx++;
@ -175,7 +175,7 @@ public class OperationClientTest {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(3, request.getParameter().size());
assertEquals("PARAM2", request.getParameter().get(0).getName());
@ -192,7 +192,7 @@ public class OperationClientTest {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM3", request.getParameter().get(0).getName());
@ -207,7 +207,7 @@ public class OperationClientTest {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(0, request.getParameter().size());
idx++;
@ -218,7 +218,7 @@ public class OperationClientTest {
requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$OP_SERVER_LIST_PARAM", value.getURI().toASCIIString());
assertEquals(0, request.getParameter().size());
idx++;
@ -253,7 +253,7 @@ public class OperationClientTest {
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent());
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/Patient/$OP_TYPE", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("PARAM1", request.getParameter().get(0).getName());

View File

@ -39,6 +39,18 @@ public class JsonParserR4Test {
return b;
}
@Test
public void testEncodeExtensionOnBinaryData() {
Binary b = new Binary();
b.getDataElement().addExtension("http://foo", new StringType("AAA"));
String output = ourCtx.newJsonParser().setSummaryMode(true).encodeResourceToString(b);
assertEquals("{\"resourceType\":\"Binary\",\"meta\":{\"tag\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/v3-ObservationValue\",\"code\":\"SUBSETTED\",\"display\":\"Resource encoded in summary mode\"}]}}", output);
output = ourCtx.newJsonParser().setDontEncodeElements(Sets.newHashSet("*.id", "*.meta")).encodeResourceToString(b);
assertEquals("{\"resourceType\":\"Binary\",\"_data\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}", output);
}
@Test
public void testDontStripVersions() {
FhirContext ctx = FhirContext.forR4();

View File

@ -1,12 +1,13 @@
package ca.uhn.fhir.rest.client;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
@ -90,13 +91,36 @@ public class BinaryClientTest {
}
@Test
public void testCreateWithNoBytes() throws Exception {
Binary res = new Binary();
res.setContentType("image/png");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML));
when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {}));
IClient client = mtCtx.newRestfulClient(IClient.class, "http://foo");
client.create(res);
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo/Binary", post.getURI().toString());
assertThat(capt.getValue().getFirstHeader("Content-Type").getValue(), containsString(Constants.CT_FHIR_JSON_NEW));
assertEquals("{\"resourceType\":\"Binary\",\"contentType\":\"image/png\"}", IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8));
}
private interface IClient extends IBasicClient {
@Read(type = Binary.class)
public Binary read(@IdParam IdType theBinary);
Binary read(@IdParam IdType theBinary);
@Create(type = Binary.class)
public MethodOutcome create(@ResourceParam Binary theBinary);
MethodOutcome create(@ResourceParam Binary theBinary);
}

View File

@ -123,7 +123,7 @@ public class ClientHeadersR4Test {
assertNotNull(resp);
assertEquals(1, ourHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals("application/fhir+xml; charset=UTF-8", ourHeaders.get(Constants.HEADER_CONTENT_TYPE).get(0));
assertEquals("application/fhir+json; charset=UTF-8", ourHeaders.get(Constants.HEADER_CONTENT_TYPE).get(0));
}
@Before

View File

@ -59,7 +59,7 @@ public class ClientMimetypeR4Test {
Patient pt = new Patient();
pt.getText().setDivAsString("A PATIENT");
MethodOutcome outcome = client.create().resource(pt).execute();
MethodOutcome outcome = client.create().resource(pt).encodedXml().execute();
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
@ -79,7 +79,7 @@ public class ClientMimetypeR4Test {
Patient pt = new Patient();
pt.getText().setDivAsString("A PATIENT");
MethodOutcome outcome = client.create().resource(pt).execute();
MethodOutcome outcome = client.create().resource(pt).encodedXml().execute();
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());

View File

@ -157,9 +157,9 @@ public class ClientR4Test {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("{\"resourceType\":\"Patient\""));
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("200", response.getId().getVersionIdPart());
}
@ -205,7 +205,7 @@ public class ClientR4Test {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("\"Patient"));
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
assertEquals("200", response.getId().getVersionIdPart());
}
@ -1046,10 +1046,10 @@ public class ClientR4Test {
assertEquals(HttpPut.class, capt.getValue().getClass());
HttpPut post = (HttpPut) capt.getValue();
assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/100"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("\"Patient"));
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
assertEquals("200", response.getId().getVersionIdPart());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
}
/**
@ -1114,7 +1114,7 @@ public class ClientR4Test {
assertEquals(HttpPut.class, capt.getValue().getClass());
HttpPut post = (HttpPut) capt.getValue();
assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/100"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("\"Patient"));
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
assertEquals("200", response.getId().getVersionIdPart());
}
@ -1138,7 +1138,7 @@ public class ClientR4Test {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/$validate"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("\"Patient"));
assertNull(response.getOperationOutcome());
assertNull(response.getResource());
}
@ -1189,7 +1189,7 @@ public class ClientR4Test {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/$validate"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("\"Patient"));
assertNotNull(response.getOperationOutcome());
assertEquals("ALL GOOD", ((OperationOutcome) response.getOperationOutcome()).getIssueFirstRep().getDiagnostics());
assertNull(response.getResource());

View File

@ -202,9 +202,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Binary output = ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt));
assertEquals(Constants.CT_FHIR_JSON, output.getContentType());
Patient outputPt = (Patient) ourCtx.newJsonParser().parseResource(new String(output.getContent(), "UTF-8"));
@ -241,9 +241,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourCtx.newJsonParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
}
@ -353,7 +353,7 @@ public class GenericClientR4Test {
assertEquals(myAnswerCount, capt.getAllValues().size());
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(Constants.CT_FHIR_XML_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals(Constants.CT_FHIR_JSON_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("http://foo.com/base/Patient/222/_history/3", capt.getAllValues().get(1).getURI().toASCIIString());
}
@ -801,9 +801,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Patient/123/$opname", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newXmlParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newJsonParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("name", output.getParameterFirstRep().getName());
assertEquals("true", ((IPrimitiveType<?>) output.getParameterFirstRep().getValue()).getValueAsString());
}
@ -845,9 +845,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Patient/123/_history/456/$opname", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newXmlParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newJsonParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("name", output.getParameterFirstRep().getName());
assertEquals("true", ((IPrimitiveType<?>) output.getParameterFirstRep().getValue()).getValueAsString());
}
@ -889,9 +889,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/$opname", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newXmlParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newJsonParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("name", output.getParameterFirstRep().getName());
assertEquals("true", ((IPrimitiveType<?>) output.getParameterFirstRep().getValue()).getValueAsString());
}
@ -1012,9 +1012,9 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Patient/$opname", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newXmlParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
Parameters output = ourCtx.newJsonParser().parseResource(Parameters.class, extractBodyAsString(capt));
assertEquals("name", output.getParameterFirstRep().getName());
assertEquals("true", ((IPrimitiveType<?>) output.getParameterFirstRep().getValue()).getValueAsString());
}
@ -1342,6 +1342,7 @@ public class GenericClientR4Test {
.update()
.resource(bundle)
.prefer(PreferReturnEnum.REPRESENTATION)
.encodedXml()
.execute();
HttpPut httpRequest = (HttpPut) capt.getValue();
@ -2109,10 +2110,10 @@ public class GenericClientR4Test {
assertEquals("http://example.com/fhir/Patient/111", capt.getAllValues().get(0).getURI().toASCIIString());
validateUserAgent(capt);
assertEquals("application/fhir+xml;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
assertEquals("application/fhir+json;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
String body = extractBodyAsString(capt);
assertThat(body, containsString("<id value=\"111\"/>"));
assertThat(body, containsString("\"id\":\"111\""));
}
@Test

View File

@ -324,7 +324,7 @@ public class GenericClientTest {
assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString());
assertEquals("POST", capt.getValue().getMethod());
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("myHeaderValue", capt.getValue().getFirstHeader("myHeaderName").getValue());
count++;
@ -335,7 +335,7 @@ public class GenericClientTest {
client.create().resource(p1).execute();
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(1).getURI().toString());
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
count++;
String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>";
@ -583,7 +583,7 @@ public class GenericClientTest {
assertEquals("http://example.com/fhir/MessageHeader/$process-message", capt.getAllValues().get(count).getURI().toString());
String requestContent = IOUtils.toString(((HttpPost) capt.getAllValues().get(count)).getEntity().getContent(), Charsets.UTF_8);
assertThat(requestContent, startsWith("<Parameters xmlns=\"http://hl7.org/fhir\">"));
assertThat(requestContent, containsString("{\"resourceType\":\"Parameters\""));
count++;
}
@ -1565,7 +1565,7 @@ public class GenericClientTest {
}
@Test
public void testTransaction() throws Exception {
public void testTransactionJson() throws Exception {
Bundle input = createTransactionBundleInput();
Bundle output = createTransactionBundleOutput();
@ -1585,7 +1585,7 @@ public class GenericClientTest {
assertEquals("http://example.com/fhir", capt.getValue().getURI().toString());
assertEquals(input.getEntry().get(0).getResource().getId(), response.getEntry().get(0).getResource().getId());
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
}
@ -1606,6 +1606,7 @@ public class GenericClientTest {
Bundle response = client.transaction()
.withBundle(input)
.encodedXml()
.execute();
assertEquals("http://example.com/fhir", capt.getValue().getURI().toString());
@ -1646,7 +1647,7 @@ public class GenericClientTest {
assertEquals(1, capt.getAllValues().size());
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
count++;
MethodOutcome outcome = client.update().resource(p1).execute();

View File

@ -144,7 +144,7 @@ public class NonGenericClientR4Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
String request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"FAM\"}]}}]}", request);
idx = 1;
outcome = client.validate(patient, ValidationModeEnum.CREATE, "http://foo");
@ -152,7 +152,7 @@ public class NonGenericClientR4Test {
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter><parameter><name value=\"mode\"/><valueString value=\"create\"/></parameter><parameter><name value=\"profile\"/><valueString value=\"http://foo\"/></parameter></Parameters>", request);
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"FAM\"}]}},{\"name\":\"mode\",\"valueString\":\"create\"},{\"name\":\"profile\",\"valueString\":\"http://foo\"}]}", request);
}

View File

@ -97,7 +97,7 @@ public class OperationClientR4Test {
String requestBody = IOUtils.toString(value.getEntity().getContent(), Charsets.UTF_8);
IOUtils.closeQuietly(value.getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());
@ -165,7 +165,7 @@ public class OperationClientR4Test {
String requestBody = IOUtils.toString(value.getEntity().getContent(), Charsets.UTF_8);
IOUtils.closeQuietly(value.getEntity().getContent());
ourLog.info(requestBody);
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
Parameters request = ourCtx.newJsonParser().parseResource(Parameters.class, requestBody);
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
assertEquals(2, request.getParameter().size());
assertEquals("valstr", request.getParameter().get(0).getName());

View File

@ -80,7 +80,7 @@ public class TransactionClientTest {
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo", post.getURI().toString());
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, new InputStreamReader(post.getEntity().getContent()));
Bundle bundle = ctx.newJsonParser().parseResource(Bundle.class, new InputStreamReader(post.getEntity().getContent()));
ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle));
assertEquals(2, bundle.getEntry().size());
@ -119,7 +119,7 @@ public class TransactionClientTest {
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo", post.getURI().toString());
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, new InputStreamReader(post.getEntity().getContent()));
Bundle bundle = ctx.newJsonParser().parseResource(Bundle.class, new InputStreamReader(post.getEntity().getContent()));
ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle));
assertEquals(2, bundle.getEntry().size());

View File

@ -120,6 +120,12 @@ public class ${className} extends ca.uhn.fhir.model.${version}.resource.BaseReso
return this;
}
@Override
public boolean hasData() {
return getContent() != null;
}
#end
#if ( ${className} == "Bundle" )
/**

View File

@ -45,6 +45,13 @@
should be an easy fix to existing code.
]]>
</action>
<action type="change">
<![CDATA[
<b>Breaking Change</b>:
The HAPI FHIR REST client and server will now default to using JSON encoding instead of XML when
the user has not explicitly configured a preference.
]]>
</action>
<action type="add">
A new interceptor called
<![CDATA[<code>ConsentInterceptor</code>]]> has been added. This interceptor allows
@ -111,10 +118,6 @@
can delete them. The boolean return value of the hook indicates whether the server should try
checking for conflicts again (true means try again).
</action>
<action type="change">
The default RestfulServer encoding has been changed from XML to JSON in order to
reflect the most common usage.
</action>
<action type="add" issue="1336">
The HAPI FHIR unit test suite has been refactored to no longer rely on PortUtil to
assign a free port. This should theoretically result in fewer failed builds resulting from
@ -332,6 +335,7 @@
a narrative on an untitled DiagnosticReport were fixed. Thanks to GitHub
user @navyflower for reporting!
</action>
</release>
<release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix">