Add support for Binary X-Security-Context header in server
This commit is contained in:
parent
256d541dda
commit
75bfb6af1b
|
@ -118,6 +118,7 @@
|
|||
</ignoredDependencies>
|
||||
<ignoredResources>
|
||||
<ignoredResource>changelog.txt</ignoredResource>
|
||||
<ignoredResource>javac.bat</ignoredResource>
|
||||
</ignoredResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -78,6 +78,10 @@ public enum FhirVersionEnum {
|
|||
return myVersionImplementation;
|
||||
}
|
||||
|
||||
public boolean isEqualOrNewerThan(FhirVersionEnum theVersion) {
|
||||
return ordinal() >= theVersion.ordinal();
|
||||
}
|
||||
|
||||
public boolean isEquivalentTo(FhirVersionEnum theVersion) {
|
||||
if (this.equals(theVersion)) {
|
||||
return true;
|
||||
|
|
|
@ -19,19 +19,6 @@ package ca.uhn.fhir.parser;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
|
||||
|
@ -46,10 +33,27 @@ import ca.uhn.fhir.parser.json.*;
|
|||
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.BinaryUtil;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.ID_DATATYPE;
|
||||
import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
import java.lang.reflect.Method;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
/**
|
||||
* This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use
|
||||
|
@ -89,7 +93,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private boolean addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?, ?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier, CompositeChildElement theChildElem,
|
||||
CompositeChildElement theParent) {
|
||||
CompositeChildElement theParent) {
|
||||
if (ext.size() > 0) {
|
||||
list.ensureCapacity(valueIdx);
|
||||
while (list.size() <= valueIdx) {
|
||||
|
@ -140,12 +144,6 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException {
|
||||
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
|
||||
doEncodeResourceToJsonLikeWriter(theResource, eventWriter);
|
||||
}
|
||||
|
||||
public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
|
||||
if (myPrettyPrint) {
|
||||
theEventWriter.setPrettyPrint(myPrettyPrint);
|
||||
|
@ -157,6 +155,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
theEventWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException {
|
||||
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
|
||||
doEncodeResourceToJsonLikeWriter(theResource, eventWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
|
||||
JsonLikeStructure jsonStructure = new GsonStructure();
|
||||
|
@ -192,136 +196,136 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBase theNextValue,
|
||||
BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, boolean theSubResource, CompositeChildElement theChildElem,
|
||||
boolean theForceEmpty) throws IOException {
|
||||
BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, boolean theSubResource, CompositeChildElement theChildElem,
|
||||
boolean theForceEmpty) throws IOException {
|
||||
|
||||
switch (theChildDef.getChildType()) {
|
||||
case ID_DATATYPE: {
|
||||
IIdType value = (IIdType) theNextValue;
|
||||
String encodedValue = "id".equals(theChildName) ? value.getIdPart() : value.getValue();
|
||||
if (isBlank(encodedValue)) {
|
||||
break;
|
||||
}
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, encodedValue);
|
||||
} else {
|
||||
theEventWriter.write(encodedValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
|
||||
if (isBlank(value.getValueAsString())) {
|
||||
if (theForceEmpty) {
|
||||
theEventWriter.writeNull();
|
||||
case ID_DATATYPE: {
|
||||
IIdType value = (IIdType) theNextValue;
|
||||
String encodedValue = "id".equals(theChildName) ? value.getIdPart() : value.getValue();
|
||||
if (isBlank(encodedValue)) {
|
||||
break;
|
||||
}
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, encodedValue);
|
||||
} else {
|
||||
theEventWriter.write(encodedValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (value instanceof IBaseIntegerDatatype) {
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
|
||||
} else {
|
||||
theEventWriter.write(((IBaseIntegerDatatype) value).getValue());
|
||||
}
|
||||
} else if (value instanceof IBaseDecimalDatatype) {
|
||||
BigDecimal decimalValue = ((IBaseDecimalDatatype) value).getValue();
|
||||
decimalValue = new BigDecimal(decimalValue.toString()) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.getValueAsString();
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
|
||||
if (isBlank(value.getValueAsString())) {
|
||||
if (theForceEmpty) {
|
||||
theEventWriter.writeNull();
|
||||
}
|
||||
};
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, decimalValue);
|
||||
} else {
|
||||
theEventWriter.write(decimalValue);
|
||||
break;
|
||||
}
|
||||
} else if (value instanceof IBaseBooleanDatatype) {
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, ((IBaseBooleanDatatype) value).getValue());
|
||||
|
||||
if (value instanceof IBaseIntegerDatatype) {
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
|
||||
} else {
|
||||
theEventWriter.write(((IBaseIntegerDatatype) value).getValue());
|
||||
}
|
||||
} else if (value instanceof IBaseDecimalDatatype) {
|
||||
BigDecimal decimalValue = ((IBaseDecimalDatatype) value).getValue();
|
||||
decimalValue = new BigDecimal(decimalValue.toString()) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.getValueAsString();
|
||||
}
|
||||
};
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, decimalValue);
|
||||
} else {
|
||||
theEventWriter.write(decimalValue);
|
||||
}
|
||||
} else if (value instanceof IBaseBooleanDatatype) {
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, ((IBaseBooleanDatatype) value).getValue());
|
||||
} else {
|
||||
Boolean booleanValue = ((IBaseBooleanDatatype) value).getValue();
|
||||
if (booleanValue != null) {
|
||||
theEventWriter.write(booleanValue.booleanValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Boolean booleanValue = ((IBaseBooleanDatatype) value).getValue();
|
||||
if (booleanValue != null) {
|
||||
theEventWriter.write(booleanValue.booleanValue());
|
||||
String valueStr = value.getValueAsString();
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, valueStr);
|
||||
} else {
|
||||
theEventWriter.write(valueStr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String valueStr = value.getValueAsString();
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, valueStr);
|
||||
theEventWriter.beginObject(theChildName);
|
||||
} else {
|
||||
theEventWriter.write(valueStr);
|
||||
theEventWriter.beginObject();
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theSubResource, theChildElem);
|
||||
theEventWriter.endObject();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
if (theChildName != null) {
|
||||
theEventWriter.beginObject(theChildName);
|
||||
} else {
|
||||
theEventWriter.beginObject();
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theSubResource, theChildElem);
|
||||
theEventWriter.endObject();
|
||||
break;
|
||||
}
|
||||
case CONTAINED_RESOURCE_LIST:
|
||||
case CONTAINED_RESOURCES: {
|
||||
case CONTAINED_RESOURCE_LIST:
|
||||
case CONTAINED_RESOURCES: {
|
||||
/*
|
||||
* Disabled per #103 ContainedDt value = (ContainedDt) theNextValue; for (IResource next :
|
||||
* value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; }
|
||||
* encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true,
|
||||
* fixContainedResourceId(next.getId().getValue())); }
|
||||
*/
|
||||
List<IBaseResource> containedResources = getContainedResources().getContainedResources();
|
||||
if (containedResources.size() > 0) {
|
||||
beginArray(theEventWriter, theChildName);
|
||||
List<IBaseResource> containedResources = getContainedResources().getContainedResources();
|
||||
if (containedResources.size() > 0) {
|
||||
beginArray(theEventWriter, theChildName);
|
||||
|
||||
for (IBaseResource next : containedResources) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theEventWriter, null, true, false, fixContainedResourceId(resourceId.getValue()));
|
||||
}
|
||||
for (IBaseResource next : containedResources) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theEventWriter, null, true, false, fixContainedResourceId(resourceId.getValue()));
|
||||
}
|
||||
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML_HL7ORG:
|
||||
case PRIMITIVE_XHTML: {
|
||||
if (!isSuppressNarratives()) {
|
||||
IPrimitiveType<?> dt = (IPrimitiveType<?>) theNextValue;
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, dt.getValueAsString());
|
||||
} else {
|
||||
theEventWriter.write(dt.getValueAsString());
|
||||
}
|
||||
} else {
|
||||
if (theChildName != null) {
|
||||
// do nothing
|
||||
} else {
|
||||
theEventWriter.writeNull();
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE:
|
||||
IBaseResource resource = (IBaseResource) theNextValue;
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
|
||||
encodeResourceToJsonStreamWriter(def, resource, theEventWriter, theChildName, false, true);
|
||||
break;
|
||||
case UNDECL_EXT:
|
||||
default:
|
||||
throw new IllegalStateException("Should not have this state here: " + theChildDef.getChildType().name());
|
||||
case PRIMITIVE_XHTML_HL7ORG:
|
||||
case PRIMITIVE_XHTML: {
|
||||
if (!isSuppressNarratives()) {
|
||||
IPrimitiveType<?> dt = (IPrimitiveType<?>) theNextValue;
|
||||
if (theChildName != null) {
|
||||
write(theEventWriter, theChildName, dt.getValueAsString());
|
||||
} else {
|
||||
theEventWriter.write(dt.getValueAsString());
|
||||
}
|
||||
} else {
|
||||
if (theChildName != null) {
|
||||
// do nothing
|
||||
} else {
|
||||
theEventWriter.writeNull();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE:
|
||||
IBaseResource resource = (IBaseResource) theNextValue;
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
|
||||
encodeResourceToJsonStreamWriter(def, resource, theEventWriter, theChildName, false, true);
|
||||
break;
|
||||
case UNDECL_EXT:
|
||||
default:
|
||||
throw new IllegalStateException("Should not have this state here: " + theChildDef.getChildType().name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, JsonLikeWriter theEventWriter,
|
||||
boolean theContainedResource, boolean theSubResource, CompositeChildElement theParent) throws IOException {
|
||||
boolean theContainedResource, boolean theSubResource, CompositeChildElement theParent) throws IOException {
|
||||
|
||||
{
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
|
@ -336,7 +340,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
|
||||
|
||||
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension")
|
||||
|| nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
|
||||
|| nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
|
||||
if (!haveWrittenExtensions) {
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem, theParent);
|
||||
haveWrittenExtensions = true;
|
||||
|
@ -452,15 +456,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
|
||||
beginArray(theEventWriter, childName);
|
||||
inArray = true;
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, theSubResource,nextChildElem, force);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, theSubResource, nextChildElem, force);
|
||||
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
|
||||
// suppress narratives from contained resources
|
||||
} else {
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, theSubResource,nextChildElem, false);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, theSubResource, nextChildElem, false);
|
||||
}
|
||||
currentChildName = childName;
|
||||
} else {
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource,theSubResource, nextChildElem, force);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, theSubResource, nextChildElem, force);
|
||||
}
|
||||
|
||||
valueIdx++;
|
||||
|
@ -542,7 +546,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, boolean theSubResource,
|
||||
CompositeChildElement theParent) throws IOException, DataFormatException {
|
||||
CompositeChildElement theParent) throws IOException, DataFormatException {
|
||||
|
||||
writeCommentsPreAndPost(theNextValue, theEventWriter);
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theSubResource, theParent);
|
||||
|
@ -555,14 +559,14 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
|
||||
if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
|
||||
throw new IllegalArgumentException(
|
||||
"This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
|
||||
"This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
doEncodeResourceToJsonLikeWriter(theResource, theJsonLikeWriter);
|
||||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull,
|
||||
boolean theContainedResource, boolean theSubResource) throws IOException {
|
||||
boolean theContainedResource, boolean theSubResource) throws IOException {
|
||||
IIdType resourceId = null;
|
||||
// if (theResource instanceof IResource) {
|
||||
// IResource res = (IResource) theResource;
|
||||
|
@ -599,7 +603,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull,
|
||||
boolean theContainedResource, boolean theSubResource, IIdType theResourceId) throws IOException {
|
||||
boolean theContainedResource, boolean theSubResource, IIdType theResourceId) throws IOException {
|
||||
if (!theContainedResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
@ -613,28 +617,28 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
write(theEventWriter, "resourceType", resDef.getName());
|
||||
if (theResourceId != null && theResourceId.hasIdPart()) {
|
||||
write(theEventWriter, "id", theResourceId.getIdPart());
|
||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null);
|
||||
boolean haveExtension = false;
|
||||
if (!extensions.isEmpty()) {
|
||||
haveExtension = true;
|
||||
}
|
||||
if (theResourceId != null && theResourceId.hasIdPart()) {
|
||||
write(theEventWriter, "id", theResourceId.getIdPart());
|
||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null);
|
||||
boolean haveExtension = false;
|
||||
if (!extensions.isEmpty()) {
|
||||
haveExtension = true;
|
||||
}
|
||||
|
||||
if (theResourceId.hasFormatComment() || haveExtension) {
|
||||
beginObject(theEventWriter, "_id");
|
||||
if (theResourceId.hasFormatComment()) {
|
||||
writeCommentsPreAndPost(theResourceId, theEventWriter);
|
||||
}
|
||||
if (haveExtension) {
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
}
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
if (theResourceId.hasFormatComment() || haveExtension) {
|
||||
beginObject(theEventWriter, "_id");
|
||||
if (theResourceId.hasFormatComment()) {
|
||||
writeCommentsPreAndPost(theResourceId, theEventWriter);
|
||||
}
|
||||
if (haveExtension) {
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
}
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
if (theResource instanceof IResource) {
|
||||
IResource resource = (IResource) theResource;
|
||||
|
@ -696,34 +700,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
}
|
||||
|
||||
if (theResource instanceof IBaseBinary) {
|
||||
IBaseBinary bin = (IBaseBinary) theResource;
|
||||
String contentType = bin.getContentType();
|
||||
if (isNotBlank(contentType)) {
|
||||
write(theEventWriter, "contentType", contentType);
|
||||
}
|
||||
String contentAsBase64 = bin.getContentAsBase64();
|
||||
if (isNotBlank(contentAsBase64)) {
|
||||
write(theEventWriter, "content", contentAsBase64);
|
||||
}
|
||||
try {
|
||||
Method getSC = bin.getClass().getMethod("getSecurityContext");
|
||||
Object securityContext = getSC.invoke(bin);
|
||||
if (securityContext != null) {
|
||||
Method getRef = securityContext.getClass().getMethod("getReference");
|
||||
String securityContextRef = (String) getRef.invoke(securityContext);
|
||||
if (securityContextRef != null) {
|
||||
beginObject(theEventWriter, "securityContext");
|
||||
writeOptionalTagWithTextNode(theEventWriter, "reference", securityContextRef);
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
|
@ -731,12 +708,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
/**
|
||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
||||
* called _name): resource extensions, and extension extensions
|
||||
*
|
||||
*
|
||||
* @param theChildElem
|
||||
* @param theParent
|
||||
*/
|
||||
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef,
|
||||
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent) throws IOException {
|
||||
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent) throws IOException {
|
||||
List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
|
||||
|
@ -753,7 +730,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions,
|
||||
CompositeChildElement theChildElem) {
|
||||
CompositeChildElement theChildElem) {
|
||||
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsNonModifier()) {
|
||||
for (IBase nextValue : nextDef.getAccessor().getValues(theResource)) {
|
||||
if (nextValue != null) {
|
||||
|
@ -777,7 +754,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void extractUndeclaredExtensions(IBase theElement, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions, CompositeChildElement theChildElem,
|
||||
CompositeChildElement theParent) {
|
||||
CompositeChildElement theParent) {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions element = (ISupportsUndeclaredExtensions) theElement;
|
||||
List<ExtensionDt> ext = element.getUndeclaredExtensions();
|
||||
|
@ -1045,78 +1022,78 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void parseExtension(ParserState<?> theState, JsonLikeArray theValues, boolean theIsModifier) {
|
||||
int allUnderscoreNames = 0;
|
||||
int handledUnderscoreNames = 0;
|
||||
private void parseExtension(ParserState<?> theState, JsonLikeArray theValues, boolean theIsModifier) {
|
||||
int allUnderscoreNames = 0;
|
||||
int handledUnderscoreNames = 0;
|
||||
|
||||
for (int i = 0; i < theValues.size(); i++) {
|
||||
JsonLikeObject nextExtObj = JsonLikeValue.asObject(theValues.get(i));
|
||||
JsonLikeValue jsonElement = nextExtObj.get("url");
|
||||
String url;
|
||||
if (null == jsonElement || !(jsonElement.isScalar())) {
|
||||
String parentElementName;
|
||||
if (theIsModifier) {
|
||||
parentElementName = "modifierExtension";
|
||||
} else {
|
||||
parentElementName = "extension";
|
||||
}
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = getExtensionUrl(jsonElement.getAsString());
|
||||
}
|
||||
theState.enteringNewElementExtension(null, url, theIsModifier, getServerBaseUrl());
|
||||
for (String next : nextExtObj.keySet()) {
|
||||
if ("url".equals(next)) {
|
||||
continue;
|
||||
} else if ("extension".equals(next)) {
|
||||
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
|
||||
parseExtension(theState, jsonVal, false);
|
||||
} else if ("modifierExtension".equals(next)) {
|
||||
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
|
||||
parseExtension(theState, jsonVal, true);
|
||||
} else if (next.charAt(0) == '_') {
|
||||
allUnderscoreNames++;
|
||||
continue;
|
||||
} else {
|
||||
JsonLikeValue jsonVal = nextExtObj.get(next);
|
||||
String alternateName = '_' + next;
|
||||
JsonLikeValue alternateVal = nextExtObj.get(alternateName);
|
||||
if (alternateVal != null) {
|
||||
handledUnderscoreNames++;
|
||||
}
|
||||
parseChildren(theState, next, jsonVal, alternateVal, alternateName, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < theValues.size(); i++) {
|
||||
JsonLikeObject nextExtObj = JsonLikeValue.asObject(theValues.get(i));
|
||||
JsonLikeValue jsonElement = nextExtObj.get("url");
|
||||
String url;
|
||||
if (null == jsonElement || !(jsonElement.isScalar())) {
|
||||
String parentElementName;
|
||||
if (theIsModifier) {
|
||||
parentElementName = "modifierExtension";
|
||||
} else {
|
||||
parentElementName = "extension";
|
||||
}
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = getExtensionUrl(jsonElement.getAsString());
|
||||
}
|
||||
theState.enteringNewElementExtension(null, url, theIsModifier, getServerBaseUrl());
|
||||
for (String next : nextExtObj.keySet()) {
|
||||
if ("url".equals(next)) {
|
||||
continue;
|
||||
} else if ("extension".equals(next)) {
|
||||
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
|
||||
parseExtension(theState, jsonVal, false);
|
||||
} else if ("modifierExtension".equals(next)) {
|
||||
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
|
||||
parseExtension(theState, jsonVal, true);
|
||||
} else if (next.charAt(0) == '_') {
|
||||
allUnderscoreNames++;
|
||||
continue;
|
||||
} else {
|
||||
JsonLikeValue jsonVal = nextExtObj.get(next);
|
||||
String alternateName = '_' + next;
|
||||
JsonLikeValue alternateVal = nextExtObj.get(alternateName);
|
||||
if (alternateVal != null) {
|
||||
handledUnderscoreNames++;
|
||||
}
|
||||
parseChildren(theState, next, jsonVal, alternateVal, alternateName, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This happens if an element has an extension but no actual value. I.e.
|
||||
* This happens if an element has an extension but no actual value. I.e.
|
||||
* if a resource has a "_status" element but no corresponding "status"
|
||||
* element. This could be used to handle a null value with an extension
|
||||
* for example.
|
||||
*/
|
||||
if (allUnderscoreNames > handledUnderscoreNames) {
|
||||
for (String alternateName : nextExtObj.keySet()) {
|
||||
if (alternateName.startsWith("_") && alternateName.length() > 1) {
|
||||
JsonLikeValue nextValue = nextExtObj.get(alternateName);
|
||||
if (nextValue != null) {
|
||||
if (nextValue.isObject()) {
|
||||
String nextName = alternateName.substring(1);
|
||||
if (nextExtObj.get(nextName) == null) {
|
||||
theState.enteringNewElement(null, nextName);
|
||||
parseAlternates(nextValue, theState, alternateName, alternateName);
|
||||
theState.endingElement();
|
||||
}
|
||||
} else {
|
||||
getErrorHandler().incorrectJsonType(null, alternateName, ValueType.OBJECT, null, nextValue.getJsonType(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
theState.endingElement();
|
||||
}
|
||||
}
|
||||
if (allUnderscoreNames > handledUnderscoreNames) {
|
||||
for (String alternateName : nextExtObj.keySet()) {
|
||||
if (alternateName.startsWith("_") && alternateName.length() > 1) {
|
||||
JsonLikeValue nextValue = nextExtObj.get(alternateName);
|
||||
if (nextValue != null) {
|
||||
if (nextValue.isObject()) {
|
||||
String nextName = alternateName.substring(1);
|
||||
if (nextExtObj.get(nextName) == null) {
|
||||
theState.enteringNewElement(null, nextName);
|
||||
parseAlternates(nextValue, theState, alternateName, alternateName);
|
||||
theState.endingElement();
|
||||
}
|
||||
} else {
|
||||
getErrorHandler().incorrectJsonType(null, alternateName, ValueType.OBJECT, null, nextValue.getJsonType(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
theState.endingElement();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseFhirComments(JsonLikeValue theObject, ParserState<?> theState) {
|
||||
if (theObject.isArray()) {
|
||||
|
@ -1270,7 +1247,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonLikeWriter theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
|
||||
List<HeldExtension> modifierExtensions) throws IOException {
|
||||
List<HeldExtension> modifierExtensions) throws IOException {
|
||||
if (extensions.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "extension");
|
||||
for (HeldExtension next : extensions) {
|
||||
|
@ -1344,6 +1321,28 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
return url1.compareTo(url2);
|
||||
}
|
||||
|
||||
private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition<?> def, final String childName) throws IOException {
|
||||
if (def.getChildType().equals(ID_DATATYPE) || def.getChildType().equals(PRIMITIVE_DATATYPE)) {
|
||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theValue, extensions, modifierExtensions, myParent, null);
|
||||
// Declared extensions
|
||||
if (def != null) {
|
||||
extractDeclaredExtensions(theValue, def, extensions, modifierExtensions, myParent);
|
||||
}
|
||||
boolean haveContent = false;
|
||||
if (!extensions.isEmpty() || !modifierExtensions.isEmpty()) {
|
||||
haveContent = true;
|
||||
}
|
||||
if (haveContent) {
|
||||
beginObject(theEventWriter, '_' + childName);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
|
||||
if (myUndeclaredExtension != null) {
|
||||
writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension);
|
||||
|
@ -1357,7 +1356,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
/*
|
||||
* This makes sure that even if the extension contains a reference to a contained
|
||||
* resource which has a HAPI-assigned ID we'll still encode that ID.
|
||||
*
|
||||
*
|
||||
* See #327
|
||||
*/
|
||||
List<? extends IBase> preProcessedValue = preProcessValues(myDef, theResource, Collections.singletonList(myValue), myChildElem);
|
||||
|
@ -1383,7 +1382,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
} else {
|
||||
String childName = myDef.getChildNameByDatatype(myValue.getClass());
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, false, myParent, false);
|
||||
managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName);
|
||||
managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName);
|
||||
}
|
||||
|
||||
theEventWriter.endObject();
|
||||
|
@ -1438,34 +1437,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
|
||||
}
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, false, myParent, false);
|
||||
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName);
|
||||
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName);
|
||||
}
|
||||
|
||||
// theEventWriter.name(myUndeclaredExtension.get);
|
||||
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
|
||||
private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition<?> def, final String childName) throws IOException {
|
||||
if (def.getChildType().equals(ID_DATATYPE) || def.getChildType().equals(PRIMITIVE_DATATYPE)) {
|
||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
// Undeclared extensions
|
||||
extractUndeclaredExtensions(theValue, extensions, modifierExtensions, myParent, null);
|
||||
// Declared extensions
|
||||
if (def != null) {
|
||||
extractDeclaredExtensions(theValue, def, extensions, modifierExtensions, myParent);
|
||||
}
|
||||
boolean haveContent = false;
|
||||
if (!extensions.isEmpty() || !modifierExtensions.isEmpty()) {
|
||||
haveContent = true;
|
||||
}
|
||||
if (haveContent) {
|
||||
beginObject(theEventWriter, '_' + childName);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,7 @@ public class Constants {
|
|||
public static final String OO_INFOSTATUS_PROCESSING = "processing";
|
||||
public static final String PARAM_GRAPHQL_QUERY = "query";
|
||||
public static final String HEADER_X_CACHE = "X-Cache";
|
||||
public static final String HEADER_X_SECURITY_CONTEXT = "X-Security-Context";
|
||||
|
||||
static {
|
||||
CHARSET_UTF8 = Charset.forName(CHARSET_NAME_UTF8);
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
public class BinaryUtil {
|
||||
|
||||
private BinaryUtil() {
|
||||
// non instantiable
|
||||
}
|
||||
|
||||
public static IBaseReference getSecurityContext(FhirContext theCtx, IBaseBinary theBinary) {
|
||||
RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
|
||||
BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
|
||||
|
||||
List<IBase> values = child.getAccessor().getValues(theBinary);
|
||||
IBaseReference retVal = null;
|
||||
if (values.size() > 0) {
|
||||
retVal = (IBaseReference) values.get(0);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static IBaseBinary newBinary(FhirContext theCtx) {
|
||||
return (IBaseBinary) theCtx.getResourceDefinition("Binary").newInstance();
|
||||
}
|
||||
|
||||
public static void setSecurityContext(FhirContext theCtx, IBaseBinary theBinary, String theSecurityContext) {
|
||||
RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
|
||||
BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
|
||||
|
||||
BaseRuntimeElementDefinition<?> referenceDef = theCtx.getElementDefinition("reference");
|
||||
IBaseReference reference = (IBaseReference) referenceDef.newInstance();
|
||||
child.getMutator().addValue(theBinary, reference);
|
||||
|
||||
reference.setReference(theSecurityContext);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,8 +20,12 @@ package ca.uhn.fhir.jpa.search;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
@ -34,11 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Deletes old searches
|
||||
|
@ -46,26 +46,21 @@ import ca.uhn.fhir.jpa.entity.Search;
|
|||
public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
||||
public static final long DEFAULT_CUTOFF_SLACK = 10 * DateUtils.MILLIS_PER_SECOND;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvcImpl.class);
|
||||
|
||||
private static Long ourNowForUnitTests;
|
||||
/*
|
||||
* We give a bit of extra leeway just to avoid race conditions where a query result
|
||||
* is being reused (because a new client request came in with the same params) right before
|
||||
* the result is to be deleted
|
||||
*/
|
||||
private long myCutoffSlack = DEFAULT_CUTOFF_SLACK;
|
||||
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchIncludeDao mySearchIncludeDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchResultDao mySearchResultDao;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
|
@ -87,7 +82,7 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
|||
if (myDaoConfig.getReuseCachedSearchResultsForMillis() != null) {
|
||||
cutoffMillis = Math.max(cutoffMillis, myDaoConfig.getReuseCachedSearchResultsForMillis());
|
||||
}
|
||||
final Date cutoff = new Date((System.currentTimeMillis() - cutoffMillis) - myCutoffSlack);
|
||||
final Date cutoff = new Date((now() - cutoffMillis) - myCutoffSlack);
|
||||
|
||||
ourLog.debug("Searching for searches which are before {}", cutoff);
|
||||
|
||||
|
@ -131,4 +126,19 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
|||
myCutoffSlack = theCutoffSlack;
|
||||
}
|
||||
|
||||
private static long now() {
|
||||
if (ourNowForUnitTests != null) {
|
||||
return ourNowForUnitTests;
|
||||
}
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is for unit tests only, do not call otherwise
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static void setNowForUnitTests(Long theNowForUnitTests) {
|
||||
ourNowForUnitTests = theNowForUnitTests;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -130,4 +130,19 @@ public class TestUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void sleepAtLeast(int theMillis) {
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() <= start + theMillis) {
|
||||
try {
|
||||
long timeSinceStarted = System.currentTimeMillis() - start;
|
||||
long timeToSleep = Math.max(0, theMillis - timeSinceStarted);
|
||||
ourLog.info("Sleeping for {}ms", timeToSleep);
|
||||
Thread.sleep(timeToSleep);
|
||||
} catch (InterruptedException theE) {
|
||||
theE.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
|
@ -18,15 +22,13 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
|
||||
public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoDstu3SearchPageExpiryTest.class);
|
||||
|
||||
@After()
|
||||
public void after() {
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(StaleSearchDeletingSvcImpl.DEFAULT_CUTOFF_SLACK);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(null);
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -35,48 +37,9 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterSingleUse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(500);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(750);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,6 +61,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(1000L);
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(500L);
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
final String searchUuid1;
|
||||
{
|
||||
|
@ -109,7 +73,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
Validate.notBlank(searchUuid1);
|
||||
}
|
||||
|
||||
Thread.sleep(250);
|
||||
sleepAtLeast(250);
|
||||
|
||||
String searchUuid2;
|
||||
{
|
||||
|
@ -122,7 +86,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
Thread.sleep(500);
|
||||
sleepAtLeast(500);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
|
@ -139,18 +103,31 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
|
||||
// Search just got used so it shouldn't be deleted
|
||||
|
||||
Thread.sleep(750);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(searchUuid3));
|
||||
}
|
||||
});
|
||||
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 1400);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(searchUuid1));
|
||||
assertNotNull(mySearchEntityDao.findByUuid(searchUuid3));
|
||||
}
|
||||
});
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(searchUuid1));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(300);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 2200);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
|
@ -162,4 +139,63 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterSingleUse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
final StopWatch sw = new StopWatch();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(500);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull("Failed after " + sw.toString(), mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 499);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 600);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4SearchPageExpiryTest.class);
|
||||
|
||||
@After()
|
||||
public void after() {
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(StaleSearchDeletingSvcImpl.DEFAULT_CUTOFF_SLACK);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(null);
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -36,50 +38,9 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterSingleUse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
final StopWatch sw = new StopWatch();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(500);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull("Failed after " + sw.toString(), mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(750);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -101,6 +62,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(1000L);
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(500L);
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
final String searchUuid1;
|
||||
{
|
||||
|
@ -112,7 +74,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
Validate.notBlank(searchUuid1);
|
||||
}
|
||||
|
||||
Thread.sleep(250);
|
||||
sleepAtLeast(250);
|
||||
|
||||
String searchUuid2;
|
||||
{
|
||||
|
@ -125,7 +87,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
Thread.sleep(500);
|
||||
sleepAtLeast(500);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
|
@ -150,7 +112,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
});
|
||||
|
||||
Thread.sleep(750);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 1400);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
|
@ -166,7 +128,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
});
|
||||
|
||||
Thread.sleep(300);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 2200);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
|
@ -178,4 +140,63 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterSingleUse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
final StopWatch sw = new StopWatch();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(500);
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull("Failed after " + sw.toString(), mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 499);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
StaleSearchDeletingSvcImpl.setNowForUnitTests(start + 600);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ca.uhn.fhir.util.BinaryUtil;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
@ -580,10 +581,17 @@ public class RestfulServerUtils {
|
|||
} else {
|
||||
contentType = Constants.CT_OCTET_STREAM;
|
||||
}
|
||||
|
||||
// Force binary resources to download - This is a security measure to prevent
|
||||
// malicious images or HTML blocks being served up as content.
|
||||
response.addHeader(Constants.HEADER_CONTENT_DISPOSITION, "Attachment;");
|
||||
|
||||
IBaseReference securityContext = BinaryUtil.getSecurityContext(theServer.getFhirContext(), bin);
|
||||
String securityContextRef = securityContext.getReferenceElement().getValue();
|
||||
if (isNotBlank(securityContextRef)) {
|
||||
response.addHeader(Constants.HEADER_X_SECURITY_CONTEXT, securityContextRef);
|
||||
}
|
||||
|
||||
return response.sendAttachmentResponse(bin, theStausCode, contentType);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,24 +149,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
|
||||
return theRequest.getResponse().streamResponseAsResource(response, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, null, theRequest.isRespondGzip(), isAddContentLocationHeader());
|
||||
|
||||
// DSTU1 Bundle
|
||||
// // Is this request coming from a browser
|
||||
// String uaHeader = theRequest.getHeader("user-agent");
|
||||
// boolean requestIsBrowser = false;
|
||||
// if (uaHeader != null && uaHeader.contains("Mozilla")) {
|
||||
// requestIsBrowser = true;
|
||||
// }
|
||||
//
|
||||
// for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
|
||||
// IServerInterceptor next = theServer.getInterceptors().get(i);
|
||||
// boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getDstu1Bundle());
|
||||
// if (!continueProcessing) {
|
||||
// ourLog.debug("Interceptor {} returned false, not continuing processing");
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return theRequest.getResponse().streamResponseAsBundle(responseObject.getDstu1Bundle(), summaryMode, theRequest.isRespondGzip(), requestIsBrowser);
|
||||
}
|
||||
|
||||
public IBaseResource doInvokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) {
|
||||
|
|
|
@ -19,7 +19,24 @@ package ca.uhn.fhir.rest.server.method;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.BinaryUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -30,27 +47,8 @@ import java.lang.reflect.Modifier;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class ResourceParameter implements IParameter {
|
||||
|
||||
|
@ -193,11 +191,22 @@ public class ResourceParameter implements IParameter {
|
|||
String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
|
||||
if (EncodingEnum.forContentTypeStrict(ct) == null) {
|
||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||
IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
|
||||
IBaseBinary binary = BinaryUtil.newBinary(ctx);
|
||||
binary.setId(theRequest.getId());
|
||||
binary.setContentType(ct);
|
||||
binary.setContent(theRequest.loadRequestContents());
|
||||
retVal = binary;
|
||||
|
||||
/*
|
||||
* Security context header, which is only in
|
||||
* DSTU3+
|
||||
*/
|
||||
if (ctx.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
||||
String securityContext = theRequest.getHeader(Constants.HEADER_X_SECURITY_CONTEXT);
|
||||
if (isNotBlank(securityContext)) {
|
||||
BinaryUtil.setSecurityContext(ctx, binary, securityContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,14 +51,14 @@ import static org.mockito.Matchers.isNull;
|
|||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class JsonParserDstu3Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu3Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* See #563
|
||||
|
@ -77,22 +77,6 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #720
|
||||
*/
|
||||
@Test
|
||||
public void testParseCustomResourceType() {
|
||||
String input = "{\"resourceType\":\"Bug720ResourceType\",\"meta\":{\"profile\":[\"http://example.com/StructureDefinition/dontuse#Bug720ResourceType\"]},\"supportedVersion\":\"2.5.x\",\"templatesConsentTemplate\":[{\"domainName\":\"name\",\"Name\":\"template_01\",\"version\":\"1.0\",\"title\":\"title\",\"comment\":\"comment\",\"contact\":{\"resourceType\":\"Person\",\"name\":[{\"family\":\"Mustermann\",\"given\":[\"Max\"]}],\"telecom\":[{\"system\":\"email\",\"value\":\"max.mustermann@mail.de\"},{\"system\":\"phone\",\"value\":\"+49 1234 23232\"}],\"address\":[{\"text\":\"street 1-2\",\"city\":\"city\",\"postalCode\":\"12345\",\"country\":\"Germany\"}]}}]}";
|
||||
Bug720ResourceType parsed = ourCtx.newJsonParser().parseResource(Bug720ResourceType.class, input);
|
||||
|
||||
assertEquals(1, parsed.getTemplates().size());
|
||||
assertEquals(Bug720Datatype.class, parsed.getTemplates().get(0).getClass());
|
||||
assertEquals("Mustermann", ((Bug720Datatype)parsed.getTemplates().get(0)).getContact().getNameFirstRep().getFamily());
|
||||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #563
|
||||
*/
|
||||
|
@ -110,6 +94,26 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
String output = parser.encodeResourceToString(fhirPat);
|
||||
System.out.println("output: " + output);
|
||||
|
||||
// Deserialize then check that valueReference value is still correct
|
||||
fhirPat = parser.parseResource(Patient.class, output);
|
||||
|
||||
List<Extension> extlst = fhirPat.getExtensionsByUrl("x1");
|
||||
Assert.assertEquals(1, extlst.size());
|
||||
Assert.assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #544
|
||||
*/
|
||||
|
@ -271,12 +275,12 @@ public class JsonParserDstu3Test {
|
|||
|
||||
String enc = ourCtx.newJsonParser().encodeResourceToString(patient);
|
||||
assertThat(enc, Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}",
|
||||
"{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}"));
|
||||
"{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}"));
|
||||
assertThat(enc, Matchers.stringContainsInOrder("\"modifierExtension\":[" + "{" + "\"url\":\"http://example.com/extensions#modext\"," + "\"valueDate\":\"1995-01-02\"" + "}" + "],"));
|
||||
assertThat(enc,
|
||||
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{"
|
||||
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
|
||||
+ "]" + "}"));
|
||||
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{"
|
||||
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
|
||||
+ "]" + "}"));
|
||||
|
||||
/*
|
||||
* Now parse this back
|
||||
|
@ -334,36 +338,36 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(enc);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(enc, stringContainsInOrder("\"meta\": {",
|
||||
"\"profile\": [",
|
||||
"\"http://foo/Profile1\",",
|
||||
"\"http://foo/Profile2\"",
|
||||
"],",
|
||||
"\"security\": [",
|
||||
"{",
|
||||
"\"system\": \"sec_scheme1\",",
|
||||
"\"code\": \"sec_term1\",",
|
||||
"\"display\": \"sec_label1\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"system\": \"sec_scheme2\",",
|
||||
"\"code\": \"sec_term2\",",
|
||||
"\"display\": \"sec_label2\"",
|
||||
"}",
|
||||
"],",
|
||||
"\"tag\": [",
|
||||
"{",
|
||||
"\"system\": \"scheme1\",",
|
||||
"\"code\": \"term1\",",
|
||||
"\"display\": \"label1\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"system\": \"scheme2\",",
|
||||
"\"code\": \"term2\",",
|
||||
"\"display\": \"label2\"",
|
||||
"}",
|
||||
"]",
|
||||
"},"));
|
||||
assertThat(enc, stringContainsInOrder("\"meta\": {",
|
||||
"\"profile\": [",
|
||||
"\"http://foo/Profile1\",",
|
||||
"\"http://foo/Profile2\"",
|
||||
"],",
|
||||
"\"security\": [",
|
||||
"{",
|
||||
"\"system\": \"sec_scheme1\",",
|
||||
"\"code\": \"sec_term1\",",
|
||||
"\"display\": \"sec_label1\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"system\": \"sec_scheme2\",",
|
||||
"\"code\": \"sec_term2\",",
|
||||
"\"display\": \"sec_label2\"",
|
||||
"}",
|
||||
"],",
|
||||
"\"tag\": [",
|
||||
"{",
|
||||
"\"system\": \"scheme1\",",
|
||||
"\"code\": \"term1\",",
|
||||
"\"display\": \"label1\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"system\": \"scheme2\",",
|
||||
"\"code\": \"term2\",",
|
||||
"\"display\": \"label2\"",
|
||||
"}",
|
||||
"]",
|
||||
"},"));
|
||||
//@formatter:on
|
||||
|
||||
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc);
|
||||
|
@ -462,29 +466,29 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(enc);
|
||||
|
||||
//@formatter:off
|
||||
assertEquals("{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"meta\": {\n" +
|
||||
" \"security\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"SYSTEM1\",\n" +
|
||||
" \"version\": \"VERSION1\",\n" +
|
||||
" \"code\": \"CODE1\",\n" +
|
||||
" \"display\": \"DISPLAY1\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"SYSTEM2\",\n" +
|
||||
" \"version\": \"VERSION2\",\n" +
|
||||
" \"code\": \"CODE2\",\n" +
|
||||
" \"display\": \"DISPLAY2\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"name\": [\n" +
|
||||
" {\n" +
|
||||
" \"family\": \"FAMILY\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
assertEquals("{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"meta\": {\n" +
|
||||
" \"security\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"SYSTEM1\",\n" +
|
||||
" \"version\": \"VERSION1\",\n" +
|
||||
" \"code\": \"CODE1\",\n" +
|
||||
" \"display\": \"DISPLAY1\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"SYSTEM2\",\n" +
|
||||
" \"version\": \"VERSION2\",\n" +
|
||||
" \"code\": \"CODE2\",\n" +
|
||||
" \"display\": \"DISPLAY2\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"name\": [\n" +
|
||||
" {\n" +
|
||||
" \"family\": \"FAMILY\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}", enc.trim());
|
||||
//@formatter:on
|
||||
|
||||
|
@ -506,6 +510,22 @@ public class JsonParserDstu3Test {
|
|||
assertEquals("VERSION2", label.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithSecurityContext() {
|
||||
Binary bin = new Binary();
|
||||
bin.setContentType("text/plain");
|
||||
bin.setContent("Now is the time".getBytes());
|
||||
Reference securityContext = new Reference();
|
||||
securityContext.setReference("DiagnosticReport/1");
|
||||
bin.setSecurityContext(securityContext);
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(bin);
|
||||
ourLog.info(encoded);
|
||||
assertThat(encoded, containsString("Binary"));
|
||||
assertThat(encoded, containsString("\"contentType\":\"text/plain\""));
|
||||
assertThat(encoded, containsString("\"content\":\"Tm93IGlzIHRoZSB0aW1l\""));
|
||||
assertThat(encoded, containsString("\"securityContext\":{\"reference\":\"DiagnosticReport/1\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBundleNewBundleNoText() {
|
||||
|
||||
|
@ -539,22 +559,22 @@ public class JsonParserDstu3Test {
|
|||
//@formatter:off
|
||||
assertThat(encoded, stringContainsInOrder(
|
||||
"{",
|
||||
"\"resourceType\": \"Patient\",",
|
||||
"\"contained\": [",
|
||||
"{",
|
||||
"\"resourceType\": \"Condition\",",
|
||||
"\"id\": \"1\"",
|
||||
"}",
|
||||
"],",
|
||||
"\"extension\": [",
|
||||
"{",
|
||||
"\"url\": \"test\",",
|
||||
"\"valueReference\": {",
|
||||
"\"reference\": \"#1\"",
|
||||
"}",
|
||||
"}",
|
||||
"],",
|
||||
"\"birthDate\": \"2016-04-05\"",
|
||||
"\"resourceType\": \"Patient\",",
|
||||
"\"contained\": [",
|
||||
"{",
|
||||
"\"resourceType\": \"Condition\",",
|
||||
"\"id\": \"1\"",
|
||||
"}",
|
||||
"],",
|
||||
"\"extension\": [",
|
||||
"{",
|
||||
"\"url\": \"test\",",
|
||||
"\"valueReference\": {",
|
||||
"\"reference\": \"#1\"",
|
||||
"}",
|
||||
"}",
|
||||
"],",
|
||||
"\"birthDate\": \"2016-04-05\"",
|
||||
"}"
|
||||
));
|
||||
//@formatter:on
|
||||
|
@ -575,23 +595,6 @@ public class JsonParserDstu3Test {
|
|||
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
|
||||
assertEquals("{\"resourceType\":\"Binary\"}", output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithSecurityContext() {
|
||||
Binary bin = new Binary();
|
||||
bin.setContentType("text/plain");
|
||||
bin.setContent("Now is the time".getBytes());
|
||||
Reference securityContext = new Reference();
|
||||
securityContext.setReference("DiagnosticReport/1");
|
||||
bin.setSecurityContext(securityContext);
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(bin);
|
||||
assertThat(encoded, containsString("Binary"));
|
||||
assertThat(encoded, containsString("contentType"));
|
||||
assertThat(encoded, containsString("text/plain"));
|
||||
assertThat(encoded, containsString("Tm93IGlzIHRoZSB0aW1l"));
|
||||
assertThat(encoded, containsString("securityContext"));
|
||||
assertThat(encoded, containsString("{\"reference\":\"DiagnosticReport/1\"}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* #158
|
||||
|
@ -663,8 +666,8 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(val);
|
||||
|
||||
assertEquals(
|
||||
"{\"resourceType\":\"Patient\",\"id\":\"123\",\"contact\":[{\"extension\":[{\"url\":\"http://foo.com/contact-eyecolour\",\"valueIdentifier\":{\"value\":\"EYE\"}}],\"name\":{\"family\":\"FAMILY\"}}]}",
|
||||
val);
|
||||
"{\"resourceType\":\"Patient\",\"id\":\"123\",\"contact\":[{\"extension\":[{\"url\":\"http://foo.com/contact-eyecolour\",\"valueIdentifier\":{\"value\":\"EYE\"}}],\"name\":{\"family\":\"FAMILY\"}}]}",
|
||||
val);
|
||||
|
||||
FhirContext newCtx = FhirContext.forDstu3();
|
||||
PatientWithExtendedContactDstu3 actual = newCtx.newJsonParser().parseResource(PatientWithExtendedContactDstu3.class, val);
|
||||
|
@ -706,9 +709,9 @@ public class JsonParserDstu3Test {
|
|||
Patient p = new Patient();
|
||||
p.setId("Patient/B");
|
||||
p
|
||||
.addExtension()
|
||||
.setUrl("http://foo")
|
||||
.setValue(new Reference("Practitioner/A"));
|
||||
.addExtension()
|
||||
.setUrl("http://foo")
|
||||
.setValue(new Reference("Practitioner/A"));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
parser.setDontEncodeElements(new HashSet<String>(Arrays.asList("*.id", "*.meta")));
|
||||
|
@ -777,20 +780,20 @@ public class JsonParserDstu3Test {
|
|||
|
||||
//@formatter:off
|
||||
assertThat(output, stringContainsInOrder(
|
||||
"\"id\": \"1\"",
|
||||
"\"meta\"",
|
||||
"\"extension\"",
|
||||
"\"url\": \"http://exturl\"",
|
||||
"\"extension\"",
|
||||
"\"url\": \"http://subext\"",
|
||||
"\"valueString\": \"sub_ext_value\"",
|
||||
"\"code\":"
|
||||
));
|
||||
assertThat(output, not(stringContainsInOrder(
|
||||
"\"url\": \"http://exturl\"",
|
||||
",",
|
||||
"\"url\": \"http://exturl\""
|
||||
)));
|
||||
"\"id\": \"1\"",
|
||||
"\"meta\"",
|
||||
"\"extension\"",
|
||||
"\"url\": \"http://exturl\"",
|
||||
"\"extension\"",
|
||||
"\"url\": \"http://subext\"",
|
||||
"\"valueString\": \"sub_ext_value\"",
|
||||
"\"code\":"
|
||||
));
|
||||
assertThat(output, not(stringContainsInOrder(
|
||||
"\"url\": \"http://exturl\"",
|
||||
",",
|
||||
"\"url\": \"http://exturl\""
|
||||
)));
|
||||
//@formatter:on
|
||||
|
||||
obs = parser.parseResource(Observation.class, output);
|
||||
|
@ -821,17 +824,17 @@ public class JsonParserDstu3Test {
|
|||
|
||||
//@formatter:off
|
||||
assertThat(encoded, stringContainsInOrder(
|
||||
"\"resourceType\": \"Patient\"",
|
||||
"\"resourceType\": \"Patient\"",
|
||||
"\"contained\": [",
|
||||
"\"resourceType\": \"Condition\"",
|
||||
"\"id\": \"1\"",
|
||||
"\"bodySite\": [",
|
||||
"\"text\": \"BODY SITE\"",
|
||||
"\"extension\": [",
|
||||
"\"url\": \"testCondition\",",
|
||||
"\"valueReference\": {",
|
||||
"\"reference\": \"#1\"",
|
||||
"\"birthDate\": \"2016-04-14\"",
|
||||
"\"resourceType\": \"Condition\"",
|
||||
"\"id\": \"1\"",
|
||||
"\"bodySite\": [",
|
||||
"\"text\": \"BODY SITE\"",
|
||||
"\"extension\": [",
|
||||
"\"url\": \"testCondition\",",
|
||||
"\"valueReference\": {",
|
||||
"\"reference\": \"#1\"",
|
||||
"\"birthDate\": \"2016-04-14\"",
|
||||
"}"
|
||||
));
|
||||
//@formatter:on
|
||||
|
@ -1071,7 +1074,7 @@ public class JsonParserDstu3Test {
|
|||
|
||||
assertThat(encoded, containsString("Patient"));
|
||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"",
|
||||
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -1091,7 +1094,7 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(enc);
|
||||
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}",
|
||||
enc);
|
||||
enc);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1268,19 +1271,19 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testExplanationOfBenefit() {
|
||||
//@formatter:off
|
||||
String input = "{" +
|
||||
" \"resourceType\": \"ExplanationOfBenefit\"," +
|
||||
" \"insurance\": {\n" +
|
||||
" \"coverage\": {\n" +
|
||||
" \"reference\": \"Coverage/123\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"relationship\": {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/relationship\",\n" +
|
||||
" \"code\": \"1\",\n" +
|
||||
" \"display\": \"self\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
String input = "{" +
|
||||
" \"resourceType\": \"ExplanationOfBenefit\"," +
|
||||
" \"insurance\": {\n" +
|
||||
" \"coverage\": {\n" +
|
||||
" \"reference\": \"Coverage/123\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"relationship\": {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/relationship\",\n" +
|
||||
" \"code\": \"1\",\n" +
|
||||
" \"display\": \"self\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
ExplanationOfBenefit eob = ourCtx.newJsonParser().parseResource(ExplanationOfBenefit.class, input);
|
||||
|
@ -1334,14 +1337,14 @@ public class JsonParserDstu3Test {
|
|||
|
||||
// ID should be a String and communication should be an Array
|
||||
String input = "{\"resourceType\": \"Patient\",\n" +
|
||||
" \"id\": 123,\n" +
|
||||
" \"communication\": {\n" +
|
||||
" \"language\": {\n" +
|
||||
" \"text\": \"Hindi\"\n" +
|
||||
" },\n" +
|
||||
" \"preferred\": true\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
" \"id\": 123,\n" +
|
||||
" \"communication\": {\n" +
|
||||
" \"language\": {\n" +
|
||||
" \"text\": \"Hindi\"\n" +
|
||||
" },\n" +
|
||||
" \"preferred\": true\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
IParser p = ourCtx.newJsonParser();
|
||||
|
||||
|
@ -1375,14 +1378,14 @@ public class JsonParserDstu3Test {
|
|||
|
||||
// ID should be a String and communication should be an Array
|
||||
String input = "{\"resourceType\": \"Patient\",\n" +
|
||||
" \"id\": \"123\",\n" +
|
||||
" \"communication\": [{\n" +
|
||||
" \"language\": {\n" +
|
||||
" \"text\": \"Hindi\"\n" +
|
||||
" },\n" +
|
||||
" \"preferred\": true\n" +
|
||||
" }]\n" +
|
||||
"}";
|
||||
" \"id\": \"123\",\n" +
|
||||
" \"communication\": [{\n" +
|
||||
" \"language\": {\n" +
|
||||
" \"text\": \"Hindi\"\n" +
|
||||
" },\n" +
|
||||
" \"preferred\": true\n" +
|
||||
" }]\n" +
|
||||
"}";
|
||||
|
||||
IParser p = ourCtx.newJsonParser();
|
||||
|
||||
|
@ -1503,14 +1506,14 @@ public class JsonParserDstu3Test {
|
|||
@Ignore
|
||||
public void testNamespacePreservationEncode() throws Exception {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
|
||||
"<text>" +
|
||||
"<xhtml:div>" +
|
||||
"<xhtml:img src=\"foo\"/>" +
|
||||
"@fhirabend" +
|
||||
"</xhtml:div>" +
|
||||
"</text>" +
|
||||
"</Patient>";
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
|
||||
"<text>" +
|
||||
"<xhtml:div>" +
|
||||
"<xhtml:img src=\"foo\"/>" +
|
||||
"@fhirabend" +
|
||||
"</xhtml:div>" +
|
||||
"</text>" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
|
||||
|
||||
|
@ -1712,69 +1715,69 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testParseAndEncodeBundleWithUuidBase() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\n" +
|
||||
" \"resourceType\":\"Bundle\",\n" +
|
||||
" \"type\":\"document\",\n" +
|
||||
" \"entry\":[\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\":\"urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57\",\n" +
|
||||
" \"resource\":{\n" +
|
||||
" \"resourceType\":\"Composition\",\n" +
|
||||
" \"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\",\n" +
|
||||
" \"meta\":{\n" +
|
||||
" \"lastUpdated\":\"2013-05-28T22:12:21Z\"\n" +
|
||||
" },\n" +
|
||||
" \"text\":{\n" +
|
||||
" \"status\":\"generated\",\n" +
|
||||
" \"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 180f219f-97a8-486d-99d9-ed631fe4fc57</p><p><b>meta</b>: </p><p><b>date</b>: Feb 1, 2013 12:30:02 PM</p><p><b>type</b>: Discharge Summary from Responsible Clinician <span>(Details : {LOINC code '28655-9' = 'Physician attending Discharge summary)</span></p><p><b>status</b>: final</p><p><b>confidentiality</b>: N</p><p><b>author</b>: <a>Doctor Dave. Generated Summary: 23; Adam Careful </a></p><p><b>encounter</b>: <a>http://fhir.healthintersections.com.au/open/Encounter/doc-example</a></p></div>\"\n" +
|
||||
" },\n" +
|
||||
" \"date\":\"2013-02-01T12:30:02Z\",\n" +
|
||||
" \"type\":{\n" +
|
||||
" \"coding\":[\n" +
|
||||
" {\n" +
|
||||
" \"system\":\"http://loinc.org\",\n" +
|
||||
" \"code\":\"28655-9\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"text\":\"Discharge Summary from Responsible Clinician\"\n" +
|
||||
" },\n" +
|
||||
" \"status\":\"final\",\n" +
|
||||
" \"confidentiality\":\"N\",\n" +
|
||||
" \"subject\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Patient/d1\",\n" +
|
||||
" \"display\":\"Eve Everywoman\"\n" +
|
||||
" },\n" +
|
||||
" \"author\":[\n" +
|
||||
" {\n" +
|
||||
" \"reference\":\"Practitioner/example\",\n" +
|
||||
" \"display\":\"Doctor Dave\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"encounter\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Encounter/doc-example\"\n" +
|
||||
" },\n" +
|
||||
" \"section\":[\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Reason for admission\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:d0dd51d3-3ab2-4c84-b697-a630c3e40e7a\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Medications on Discharge\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:673f8db5-0ffd-4395-9657-6da00420bbc1\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Known allergies\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:68f86194-e6e1-4f65-b64a-5314256f8d7b\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
String input =
|
||||
"{\n" +
|
||||
" \"resourceType\":\"Bundle\",\n" +
|
||||
" \"type\":\"document\",\n" +
|
||||
" \"entry\":[\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\":\"urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57\",\n" +
|
||||
" \"resource\":{\n" +
|
||||
" \"resourceType\":\"Composition\",\n" +
|
||||
" \"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\",\n" +
|
||||
" \"meta\":{\n" +
|
||||
" \"lastUpdated\":\"2013-05-28T22:12:21Z\"\n" +
|
||||
" },\n" +
|
||||
" \"text\":{\n" +
|
||||
" \"status\":\"generated\",\n" +
|
||||
" \"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 180f219f-97a8-486d-99d9-ed631fe4fc57</p><p><b>meta</b>: </p><p><b>date</b>: Feb 1, 2013 12:30:02 PM</p><p><b>type</b>: Discharge Summary from Responsible Clinician <span>(Details : {LOINC code '28655-9' = 'Physician attending Discharge summary)</span></p><p><b>status</b>: final</p><p><b>confidentiality</b>: N</p><p><b>author</b>: <a>Doctor Dave. Generated Summary: 23; Adam Careful </a></p><p><b>encounter</b>: <a>http://fhir.healthintersections.com.au/open/Encounter/doc-example</a></p></div>\"\n" +
|
||||
" },\n" +
|
||||
" \"date\":\"2013-02-01T12:30:02Z\",\n" +
|
||||
" \"type\":{\n" +
|
||||
" \"coding\":[\n" +
|
||||
" {\n" +
|
||||
" \"system\":\"http://loinc.org\",\n" +
|
||||
" \"code\":\"28655-9\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"text\":\"Discharge Summary from Responsible Clinician\"\n" +
|
||||
" },\n" +
|
||||
" \"status\":\"final\",\n" +
|
||||
" \"confidentiality\":\"N\",\n" +
|
||||
" \"subject\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Patient/d1\",\n" +
|
||||
" \"display\":\"Eve Everywoman\"\n" +
|
||||
" },\n" +
|
||||
" \"author\":[\n" +
|
||||
" {\n" +
|
||||
" \"reference\":\"Practitioner/example\",\n" +
|
||||
" \"display\":\"Doctor Dave\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"encounter\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Encounter/doc-example\"\n" +
|
||||
" },\n" +
|
||||
" \"section\":[\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Reason for admission\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:d0dd51d3-3ab2-4c84-b697-a630c3e40e7a\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Medications on Discharge\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:673f8db5-0ffd-4395-9657-6da00420bbc1\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Known allergies\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:68f86194-e6e1-4f65-b64a-5314256f8d7b\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }" +
|
||||
" ]" +
|
||||
"}";
|
||||
|
@ -1794,34 +1797,34 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testParseAndEncodeComments() {
|
||||
//@formatter:off
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"id\": \"pat1\",\n" +
|
||||
" \"text\": {\n" +
|
||||
" \"status\": \"generated\",\n" +
|
||||
" \"div\": \"<div>\\n \\n <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\\n \\n </div>\"\n" +
|
||||
" },\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"fhir_comments\":[\"identifier comment 1\",\"identifier comment 2\"],\n" +
|
||||
" \"use\": \"usual\",\n" +
|
||||
" \"_use\": {\n" +
|
||||
" \"fhir_comments\":[\"use comment 1\",\"use comment 2\"]\n" +
|
||||
" },\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
|
||||
" \"code\": \"MR\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"system\": \"urn:oid:0.1.2.3.4.5.6.7\",\n" +
|
||||
" \"value\": \"654321\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"active\": true" +
|
||||
"}";
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"id\": \"pat1\",\n" +
|
||||
" \"text\": {\n" +
|
||||
" \"status\": \"generated\",\n" +
|
||||
" \"div\": \"<div>\\n \\n <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\\n \\n </div>\"\n" +
|
||||
" },\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"fhir_comments\":[\"identifier comment 1\",\"identifier comment 2\"],\n" +
|
||||
" \"use\": \"usual\",\n" +
|
||||
" \"_use\": {\n" +
|
||||
" \"fhir_comments\":[\"use comment 1\",\"use comment 2\"]\n" +
|
||||
" },\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
|
||||
" \"code\": \"MR\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"system\": \"urn:oid:0.1.2.3.4.5.6.7\",\n" +
|
||||
" \"value\": \"654321\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"active\": true" +
|
||||
"}";
|
||||
//@formatter:off
|
||||
|
||||
Patient res = ourCtx.newJsonParser().parseResource(Patient.class, input);
|
||||
|
@ -1829,33 +1832,33 @@ public class JsonParserDstu3Test {
|
|||
assertEquals("Patient/pat1", res.getId());
|
||||
assertEquals("654321", res.getIdentifier().get(0).getValue());
|
||||
assertEquals(true, res.getActive());
|
||||
|
||||
|
||||
assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
|
||||
assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
|
||||
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
|
||||
ourLog.info(encoded);
|
||||
|
||||
|
||||
//@formatter:off
|
||||
assertThat(encoded, stringContainsInOrder(
|
||||
"\"identifier\": [",
|
||||
"{",
|
||||
"\"fhir_comments\":",
|
||||
"[",
|
||||
"\"identifier comment 1\"",
|
||||
",",
|
||||
"\"identifier comment 2\"",
|
||||
"]",
|
||||
"\"use\": \"usual\",",
|
||||
"\"_use\": {",
|
||||
"\"fhir_comments\":",
|
||||
"[",
|
||||
"\"use comment 1\"",
|
||||
",",
|
||||
"\"use comment 2\"",
|
||||
"]",
|
||||
"},",
|
||||
"\"type\""
|
||||
"\"identifier\": [",
|
||||
"{",
|
||||
"\"fhir_comments\":",
|
||||
"[",
|
||||
"\"identifier comment 1\"",
|
||||
",",
|
||||
"\"identifier comment 2\"",
|
||||
"]",
|
||||
"\"use\": \"usual\",",
|
||||
"\"_use\": {",
|
||||
"\"fhir_comments\":",
|
||||
"[",
|
||||
"\"use comment 1\"",
|
||||
",",
|
||||
"\"use comment 2\"",
|
||||
"]",
|
||||
"},",
|
||||
"\"type\""
|
||||
));
|
||||
//@formatter:off
|
||||
}
|
||||
|
@ -1865,7 +1868,7 @@ public class JsonParserDstu3Test {
|
|||
Binary patient = new Binary();
|
||||
patient.setId(new IdType("http://base/Binary/11/_history/22"));
|
||||
patient.setContentType("foo");
|
||||
patient.setContent(new byte[] { 1, 2, 3, 4 });
|
||||
patient.setContent(new byte[]{1, 2, 3, 4});
|
||||
|
||||
String val = ourCtx.newJsonParser().encodeResourceToString(patient);
|
||||
|
||||
|
@ -1916,7 +1919,7 @@ public class JsonParserDstu3Test {
|
|||
"\"resourceType\":\"Patient\",",
|
||||
"\"id\":\"1\"",
|
||||
"\"reference\":\"#1\""
|
||||
));
|
||||
));
|
||||
//@formatter:on
|
||||
|
||||
o = parser.parseResource(Observation.class, enc);
|
||||
|
@ -1927,6 +1930,21 @@ public class JsonParserDstu3Test {
|
|||
assertEquals("patient family", p.getName().get(0).getFamilyElement().getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #720
|
||||
*/
|
||||
@Test
|
||||
public void testParseCustomResourceType() {
|
||||
String input = "{\"resourceType\":\"Bug720ResourceType\",\"meta\":{\"profile\":[\"http://example.com/StructureDefinition/dontuse#Bug720ResourceType\"]},\"supportedVersion\":\"2.5.x\",\"templatesConsentTemplate\":[{\"domainName\":\"name\",\"Name\":\"template_01\",\"version\":\"1.0\",\"title\":\"title\",\"comment\":\"comment\",\"contact\":{\"resourceType\":\"Person\",\"name\":[{\"family\":\"Mustermann\",\"given\":[\"Max\"]}],\"telecom\":[{\"system\":\"email\",\"value\":\"max.mustermann@mail.de\"},{\"system\":\"phone\",\"value\":\"+49 1234 23232\"}],\"address\":[{\"text\":\"street 1-2\",\"city\":\"city\",\"postalCode\":\"12345\",\"country\":\"Germany\"}]}}]}";
|
||||
Bug720ResourceType parsed = ourCtx.newJsonParser().parseResource(Bug720ResourceType.class, input);
|
||||
|
||||
assertEquals(1, parsed.getTemplates().size());
|
||||
assertEquals(Bug720Datatype.class, parsed.getTemplates().get(0).getClass());
|
||||
assertEquals("Mustermann", ((Bug720Datatype) parsed.getTemplates().get(0)).getContact().getNameFirstRep().getFamily());
|
||||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed));
|
||||
}
|
||||
|
||||
/**
|
||||
* #480
|
||||
*/
|
||||
|
@ -1987,10 +2005,10 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testParseJsonExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"extension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
"\"extension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
@ -2017,10 +2035,10 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testParseJsonModifierExtensionWithoutUrl() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
String input =
|
||||
"{\"resourceType\":\"Patient\"," +
|
||||
"\"modifierExtension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
"\"modifierExtension\":[ {\"valueDateTime\":\"2011-01-02T11:13:15\"} ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
@ -2044,24 +2062,24 @@ public class JsonParserDstu3Test {
|
|||
@Test
|
||||
public void testParseMetadata() throws Exception {
|
||||
//@formatter:off
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
" \"total\" : 1,\n" +
|
||||
" \"link\": [{\n" +
|
||||
" \"relation\" : \"self\",\n" +
|
||||
" \"url\" : \"http://localhost:52788/Binary?_pretty=true\"\n" +
|
||||
" }],\n" +
|
||||
" \"entry\" : [{\n" +
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
" \"total\" : 1,\n" +
|
||||
" \"link\": [{\n" +
|
||||
" \"relation\" : \"self\",\n" +
|
||||
" \"url\" : \"http://localhost:52788/Binary?_pretty=true\"\n" +
|
||||
" }],\n" +
|
||||
" \"entry\" : [{\n" +
|
||||
" \"fullUrl\" : \"http://foo/fhirBase2/Patient/1/_history/2\",\n" +
|
||||
" \"resource\" : {\n" +
|
||||
" \"resourceType\" : \"Patient\",\n" +
|
||||
" \"id\" : \"1\",\n" +
|
||||
" \"resource\" : {\n" +
|
||||
" \"resourceType\" : \"Patient\",\n" +
|
||||
" \"id\" : \"1\",\n" +
|
||||
" \"meta\" : {\n" +
|
||||
" \"versionId\" : \"2\",\n" +
|
||||
" \"lastUpdated\" : \"2001-02-22T11:22:33-05:00\"\n" +
|
||||
" },\n" +
|
||||
" \"birthDate\" : \"2012-01-02\"\n" +
|
||||
" },\n" +
|
||||
" },\n" +
|
||||
" \"birthDate\" : \"2012-01-02\"\n" +
|
||||
" },\n" +
|
||||
" \"search\" : {\n" +
|
||||
" \"mode\" : \"match\",\n" +
|
||||
" \"score\" : 0.123\n" +
|
||||
|
@ -2070,7 +2088,7 @@ public class JsonParserDstu3Test {
|
|||
" \"method\" : \"POST\",\n" +
|
||||
" \"url\" : \"http://foo/Patient?identifier=value\"\n" +
|
||||
" }\n" +
|
||||
" }]\n" +
|
||||
" }]\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
|
@ -2182,6 +2200,43 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWithPrecision() {
|
||||
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
|
||||
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
|
||||
|
||||
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
|
||||
assertEquals("0.000000000000000100", valueElement.getValueAsString());
|
||||
|
||||
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
|
||||
ourLog.info(str);
|
||||
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
|
||||
}
|
||||
|
||||
@Test(expected = DataFormatException.class)
|
||||
public void testParseWithTrailingContent() throws Exception {
|
||||
//@formatter:off
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
" \"total\" : 1\n" +
|
||||
"}}";
|
||||
//@formatter:on
|
||||
|
||||
Bundle b = ourCtx.newJsonParser().parseResource(Bundle.class, bundle);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));
|
||||
try {
|
||||
ourCtx.newJsonParser().parseResource(CapabilityStatement.class, input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'OBJECT'", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #344
|
||||
*/
|
||||
|
@ -2215,43 +2270,6 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWithPrecision() {
|
||||
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
|
||||
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
|
||||
|
||||
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
|
||||
assertEquals("0.000000000000000100", valueElement.getValueAsString());
|
||||
|
||||
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
|
||||
ourLog.info(str);
|
||||
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
|
||||
}
|
||||
|
||||
@Test(expected = DataFormatException.class)
|
||||
public void testParseWithTrailingContent() throws Exception {
|
||||
//@formatter:off
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
" \"total\" : 1\n" +
|
||||
"}}";
|
||||
//@formatter:on
|
||||
|
||||
Bundle b = ourCtx.newJsonParser().parseResource(Bundle.class, bundle);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));
|
||||
try {
|
||||
ourCtx.newJsonParser().parseResource(CapabilityStatement.class, input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'OBJECT'", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #144 and #146
|
||||
*/
|
||||
|
@ -2323,13 +2341,13 @@ public class JsonParserDstu3Test {
|
|||
ArgumentCaptor<ScalarType> expectedScalar = ArgumentCaptor.forClass(ScalarType.class);
|
||||
ArgumentCaptor<ScalarType> actualScalar = ArgumentCaptor.forClass(ScalarType.class);
|
||||
verify(errorHandler, atLeastOnce()).incorrectJsonType(Mockito.any(IParseLocation.class), elementName.capture(), expected.capture(), expectedScalar.capture(), actual.capture(),
|
||||
actualScalar.capture());
|
||||
actualScalar.capture());
|
||||
verify(errorHandler, atLeastOnce()).incorrectJsonType(Mockito.any(IParseLocation.class), Mockito.eq("_id"), Mockito.eq(ValueType.OBJECT), expectedScalar.capture(), Mockito.eq(ValueType.SCALAR),
|
||||
actualScalar.capture());
|
||||
actualScalar.capture());
|
||||
verify(errorHandler, atLeastOnce()).incorrectJsonType(Mockito.any(IParseLocation.class), Mockito.eq("__v"), Mockito.eq(ValueType.OBJECT), expectedScalar.capture(), Mockito.eq(ValueType.SCALAR),
|
||||
actualScalar.capture());
|
||||
actualScalar.capture());
|
||||
verify(errorHandler, atLeastOnce()).incorrectJsonType(Mockito.any(IParseLocation.class), Mockito.eq("_status"), Mockito.eq(ValueType.OBJECT), expectedScalar.capture(),
|
||||
Mockito.eq(ValueType.SCALAR), actualScalar.capture());
|
||||
Mockito.eq(ValueType.SCALAR), actualScalar.capture());
|
||||
|
||||
assertEquals("_id", elementName.getAllValues().get(0));
|
||||
assertEquals(ValueType.OBJECT, expected.getAllValues().get(0));
|
||||
|
@ -2361,26 +2379,6 @@ public class JsonParserDstu3Test {
|
|||
assertTrue(result.isSuccessful());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IParser parser = ourCtx.newJsonParser();
|
||||
|
||||
String output = parser.encodeResourceToString(fhirPat);
|
||||
System.out.println("output: " + output);
|
||||
|
||||
// Deserialize then check that valueReference value is still correct
|
||||
fhirPat = parser.parseResource(Patient.class, output);
|
||||
|
||||
List<Extension> extlst = fhirPat.getExtensionsByUrl("x1");
|
||||
Assert.assertEquals(1, extlst.size());
|
||||
Assert.assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -82,6 +82,23 @@ public class XmlParserDstu3Test {
|
|||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithSecurityContext() {
|
||||
Binary bin = new Binary();
|
||||
bin.setContentType("text/plain");
|
||||
bin.setContent("Now is the time".getBytes());
|
||||
Reference securityContext = new Reference();
|
||||
securityContext.setReference("DiagnosticReport/1");
|
||||
bin.setSecurityContext(securityContext);
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(bin);
|
||||
ourLog.info(encoded);
|
||||
assertThat(encoded, containsString("Binary"));
|
||||
assertThat(encoded, containsString("<contentType value=\"text/plain\"/>"));
|
||||
assertThat(encoded, containsString("<securityContext><reference value=\"DiagnosticReport/1\"/></securityContext>"));
|
||||
assertThat(encoded, containsString("<content value=\"Tm93IGlzIHRoZSB0aW1l\"/>"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #544
|
||||
*/
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -18,18 +20,20 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
import org.hl7.fhir.r4.model.Binary;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CreateBinaryR4Test {
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class BinaryServerR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static Binary ourLastBinary;
|
||||
|
@ -37,24 +41,73 @@ public class CreateBinaryR4Test {
|
|||
private static String ourLastBinaryString;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static IdType ourLastId;
|
||||
private static Binary ourNextBinary;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastBinary = null;
|
||||
ourLastBinaryBytes = null;
|
||||
ourLastBinaryString = null;
|
||||
ourLastId = null;
|
||||
ourNextBinary = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesBinaryContentType() throws Exception {
|
||||
public void testGetWithNoAccept() throws Exception {
|
||||
|
||||
ourNextBinary = new Binary();
|
||||
ourNextBinary.setId("Binary/A/_history/222");
|
||||
ourNextBinary.setContent(new byte[]{0, 1, 2, 3, 4});
|
||||
ourNextBinary.setSecurityContext(new Reference("Patient/1"));
|
||||
ourNextBinary.setContentType("application/foo");
|
||||
|
||||
HttpGet get = new HttpGet("http://localhost:" + ourPort + "/Binary/A");
|
||||
get.addHeader("Content-Type", "application/foo");
|
||||
CloseableHttpResponse status = ourClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("application/foo", status.getEntity().getContentType().getValue());
|
||||
assertEquals("Patient/1", status.getFirstHeader(Constants.HEADER_X_SECURITY_CONTEXT).getValue());
|
||||
assertEquals("W/\"222\"", status.getFirstHeader(Constants.HEADER_ETAG).getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Binary/A/_history/222", status.getFirstHeader(Constants.HEADER_LOCATION).getValue());
|
||||
|
||||
byte[] content = IOUtils.toByteArray(status.getEntity().getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, content);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostBinaryWithSecurityContext() throws Exception {
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new ByteArrayEntity(new byte[] { 0, 1, 2, 3, 4 }));
|
||||
post.setEntity(new ByteArrayEntity(new byte[]{0, 1, 2, 3, 4}));
|
||||
post.addHeader("Content-Type", "application/foo");
|
||||
post.addHeader(Constants.HEADER_X_SECURITY_CONTEXT, "Encounter/2");
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertNull(ourLastId);
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertEquals("Encounter/2", ourLastBinary.getSecurityContext().getReference());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinaryBytes);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostRawBytesBinaryContentType() throws Exception {
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new ByteArrayEntity(new byte[]{0, 1, 2, 3, 4}));
|
||||
post.addHeader("Content-Type", "application/foo");
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertNull(ourLastId);
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinaryBytes);
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinaryBytes);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
|
@ -64,11 +117,11 @@ public class CreateBinaryR4Test {
|
|||
* Technically the client shouldn't be doing it this way, but we'll be accepting
|
||||
*/
|
||||
@Test
|
||||
public void testRawBytesFhirContentType() throws Exception {
|
||||
public void testPostRawBytesFhirContentType() throws Exception {
|
||||
|
||||
Binary b = new Binary();
|
||||
b.setContentType("application/foo");
|
||||
b.setContent(new byte[] { 0, 1, 2, 3, 4 });
|
||||
b.setContent(new byte[]{0, 1, 2, 3, 4});
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(b);
|
||||
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
|
@ -77,14 +130,14 @@ public class CreateBinaryR4Test {
|
|||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinary.getContent());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesFhirContentTypeContainingFhir() throws Exception {
|
||||
public void testPostRawBytesFhirContentTypeContainingFhir() throws Exception {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getText().setDivAsString("A PATIENT");
|
||||
|
@ -109,13 +162,32 @@ public class CreateBinaryR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesNoContentType() throws Exception {
|
||||
public void testPostRawBytesNoContentType() throws Exception {
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new ByteArrayEntity(new byte[] { 0, 1, 2, 3, 4 }));
|
||||
post.setEntity(new ByteArrayEntity(new byte[]{0, 1, 2, 3, 4}));
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertNull(ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinary.getContent());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutBinaryWithSecurityContext() throws Exception {
|
||||
HttpPut post = new HttpPut("http://localhost:" + ourPort + "/Binary/A");
|
||||
post.setEntity(new ByteArrayEntity(new byte[]{0, 1, 2, 3, 4}));
|
||||
post.addHeader("Content-Type", "application/foo");
|
||||
post.addHeader(Constants.HEADER_X_SECURITY_CONTEXT, "Encounter/2");
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertEquals("Binary/A", ourLastId.getValue());
|
||||
assertEquals("Binary/A", ourLastBinary.getId());
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertEquals("Encounter/2", ourLastBinary.getSecurityContext().getReference());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[]{0, 1, 2, 3, 4}, ourLastBinaryBytes);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
|
@ -149,7 +221,6 @@ public class CreateBinaryR4Test {
|
|||
}
|
||||
|
||||
public static class BinaryProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createBinary(@ResourceParam Binary theBinary, @ResourceParam String theBinaryString, @ResourceParam byte[] theBinaryBytes) {
|
||||
ourLastBinary = theBinary;
|
||||
|
@ -163,6 +234,20 @@ public class CreateBinaryR4Test {
|
|||
return Binary.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Binary read(@IdParam IdType theId) {
|
||||
return ourNextBinary;
|
||||
}
|
||||
|
||||
@Update()
|
||||
public MethodOutcome updateBinary(@IdParam IdType theId, @ResourceParam Binary theBinary, @ResourceParam String theBinaryString, @ResourceParam byte[] theBinaryBytes) {
|
||||
ourLastId = theId;
|
||||
ourLastBinary = theBinary;
|
||||
ourLastBinaryString = theBinaryString;
|
||||
ourLastBinaryBytes = theBinaryBytes;
|
||||
return new MethodOutcome(new IdType("Binary/001/_history/002"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -175,6 +175,11 @@
|
|||
was not encoded correctly. Thanks to Malcolm McRoberts for the pull
|
||||
request with fix and test case!
|
||||
</action>
|
||||
<action type="add">
|
||||
The Binary resource endpoint now supports the `X-Security-Context` header when
|
||||
reading or writing Binary contents using their native Content-Type (i.e exchanging
|
||||
the raw binary with the server, as opposed to exchanging a FHIR resource).
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.0.0" date="2017-09-27">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue