package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Medication;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.CustomResource364Dstu2.CustomResource364CustomDate;
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.TestUtil;
public class CustomTypeDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeDstu2Test.class);
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
/**
* See #368
*/
@Test
public void testConstrainedFieldContainedResource() {
Medication medication = new Medication();
medication.getCode().setText("MED TEXT");
CustomMedicationOrderDstu2 mo = new CustomMedicationOrderDstu2();
mo.setMedication(new ResourceReferenceDt());
mo.getMedication().setResource(medication);
String string = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo);
ourLog.info(string);
//@formatter:on
assertThat(string, stringContainsInOrder(
"<MedicationOrder xmlns=\"http://hl7.org/fhir\">",
" <contained>",
" <Medication xmlns=\"http://hl7.org/fhir\">",
" <id value=\"1\"/>",
" <code>",
" <text value=\"MED TEXT\"/>",
" </code>",
" </Medication>",
" </contained>",
" <medication>",
" <reference value=\"#1\"/>",
" </medication>",
"</MedicationOrder>"));
//@formatter:on
mo = ourCtx.newXmlParser().parseResource(CustomMedicationOrderDstu2.class, string);
medication = (Medication) mo.getMedication().getResource();
assertNotNull(medication);
assertEquals("#1", medication.getId().getValue());
assertEquals("MED TEXT", medication.getCode().getText());
}
/**
* See #364
*/
@Test
public void testCustomTypeWithCustomDatatype() {
FhirContext context = FhirContext.forDstu2();
context.registerCustomType(CustomResource364Dstu2.class);
context.registerCustomType(CustomResource364CustomDate.class);
IParser parser = context.newXmlParser();
CustomResource364Dstu2 resource = new CustomResource364Dstu2();
resource.setBaseValues(new CustomResource364CustomDate().setDate(new DateTimeDt("2016-05-13")));
String xml = parser.encodeResourceToString(resource);
ourLog.info(xml);
//@formatter:on
assertThat(xml, stringContainsInOrder(
"<CustomResource xmlns=\"http://hl7.org/fhir\">",
"<meta><profile value=\"http://hl7.org/fhir/profiles/custom-resource\"/></meta>",
"<baseValueCustomDate><date value=\"2016-05-13\"/></baseValueCustomDate>",
"</CustomResource>"
));
//@formatter:on
CustomResource364Dstu2 parsedResource = parser.parseResource(CustomResource364Dstu2.class, xml);
assertEquals("2016-05-13", ((CustomResource364CustomDate)parsedResource.getBaseValues()).getDate().getValueAsString());
}
/**
* See #364
*/
@Test
public void testCustomTypeWithPrimitiveType() {
FhirContext context = FhirContext.forDstu2();
IParser parser = context.newXmlParser();
CustomResource364Dstu2 resource = new CustomResource364Dstu2();
resource.setBaseValues(new StringDt("2016-05-13"));
String xml = parser.encodeResourceToString(resource);
//@formatter:on
assertThat(xml, stringContainsInOrder(
"<CustomResource xmlns=\"http://hl7.org/fhir\">",
"<meta><profile value=\"http://hl7.org/fhir/profiles/custom-resource\"/></meta>",
"<baseValueString value=\"2016-05-13\"/>",
"</CustomResource>"
));
//@formatter:on
CustomResource364Dstu2 parsedResource = parser.parseResource(CustomResource364Dstu2.class, xml);
assertEquals("2016-05-13", ((StringDt)parsedResource.getBaseValues()).getValueAsString());
}
@Before
public void before() {
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
}
private String createBundle(String... theResources) {
StringBuilder b = new StringBuilder();
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
for (String next : theResources) {
b.append(" <entry>\n");
b.append(" <resource>\n");
b.append(next);
b.append(" </resource>\n");
b.append(" </entry>\n");
}
b.append("</Bundle>");
return b.toString();
}
private String createResource(boolean theWithProfile) {
StringBuilder b = new StringBuilder();
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
if (theWithProfile) {
b.append(" <meta>\n");
b.append(" <profile value=\"http://example.com/foo\"/>\n");
b.append(" </meta>\n");
}
b.append(" <extension url=\"http://example.com/BloodPressure\">\n");
b.append(" <valueQuantity>\n");
b.append(" <value value=\"110\"/>\n");
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
b.append(" <code value=\"mmHg\"/>\n");
b.append(" </valueQuantity>\n");
b.append(" </extension>\n");
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
b.append(" <valueDateTime value=\"2010-01-02\"/>\n");
b.append(" </modifierExtension>\n");
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
b.append(" <valueDateTime value=\"2014-01-26T11:11:11\"/>\n");
b.append(" </modifierExtension>\n");
b.append(" <extension url=\"http://example.com/Cholesterol\">\n");
b.append(" <valueQuantity>\n");
b.append(" <value value=\"2\"/>\n");
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
b.append(" <code value=\"mmol/l\"/>\n");
b.append(" </valueQuantity>\n");
b.append(" </extension>\n");
b.append(" <extension url=\"http://example.com/Glucose\">\n");
b.append(" <valueQuantity>\n");
b.append(" <value value=\"95\"/>\n");
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
b.append(" <code value=\"mg/dl\"/>\n");
b.append(" </valueQuantity>\n");
b.append(" </extension>\n");
b.append(" <extension url=\"http://example.com/HbA1c\">\n");
b.append(" <valueQuantity>\n");
b.append(" <value value=\"48\"/>\n");
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
b.append(" <code value=\"mmol/mol\"/>\n");
b.append(" </valueQuantity>\n");
b.append(" </extension>\n");
b.append(" <extension url=\"http://example.com/Insuline\">\n");
b.append(" <valueQuantity>\n");
b.append(" <value value=\"125\"/>\n");
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
b.append(" <code value=\"pmol/l\"/>\n");
b.append(" </valueQuantity>\n");
b.append(" </extension>\n");
b.append(" <extension url=\"http://example.com/Weight\">\n");
b.append(" <valueString value=\"185 cm\"/>\n");
b.append(" </extension>\n");
b.append(" <identifier>\n");
b.append(" <system value=\"urn:system\"/>\n");
b.append(" <value value=\"1234\"/>\n");
b.append(" </identifier>\n");
b.append(" <name>\n");
b.append(" <family value=\"Rossi\"/>\n");
b.append(" <given value=\"Mario\"/>\n");
b.append(" </name>\n");
b.append("</Patient>");
String input = b.toString();
return input;
}
@Test
public void parseBundleWithResourceDirective() {
String input = createBundle(createResource(false), createResource(true));
FhirContext ctx = FhirContext.forDstu2();
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, input);
Patient res0 = (Patient) bundle.getEntry().get(0).getResource();
assertEquals(0, res0.getMeta().getProfile().size());
List<ExtensionDt> exts = res0.getUndeclaredExtensionsByUrl("http://example.com/Weight");
assertEquals(1, exts.size());
assertEquals("185 cm", ((StringDt) exts.get(0).getValueAsPrimitive()).getValue());
MyCustomPatient res1 = (MyCustomPatient) bundle.getEntry().get(1).getResource();
assertEquals(1, res1.getMeta().getProfile().size());
assertEquals("http://example.com/foo", res1.getMeta().getProfile().get(0).getValue());
exts = res1.getUndeclaredExtensionsByUrl("http://example.com/Weight");
assertEquals(0, exts.size());
assertEquals("185 cm", res1.getWeight().getValue());
}
@Test
public void parseResourceWithDirective() {
String input = createResource(true);
FhirContext ctx = FhirContext.forDstu2();
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
MyCustomPatient parsed = (MyCustomPatient) ctx.newXmlParser().parseResource(input);
assertEquals(1, parsed.getMeta().getProfile().size());
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
List<ExtensionDt> exts = parsed.getUndeclaredExtensionsByUrl("http://example.com/Weight");
assertEquals(0, exts.size());
assertEquals("185 cm", parsed.getWeight().getValue());
}
@Test
public void parseResourceWithNoDirective() {
String input = createResource(true);
FhirContext ctx = FhirContext.forDstu2();
Patient parsed = (Patient) ctx.newXmlParser().parseResource(input);
assertEquals(1, parsed.getMeta().getProfile().size());
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
List<ExtensionDt> exts = parsed.getUndeclaredExtensionsByUrl("http://example.com/Weight");
assertEquals(1, exts.size());
assertEquals("185 cm", ((StringDt) exts.get(0).getValueAsPrimitive()).getValue());
}
@Test
public void testAccessEmptyMetaLists() {
Patient p = new Patient();
assertThat(p.getMeta().getProfile(), empty());
assertThat(p.getMeta().getFormatCommentsPost(), empty());
assertThat(p.getMeta().getFormatCommentsPre(), empty());
assertThat(p.getMeta().getLastUpdated(), nullValue());
assertThat(p.getMeta().getSecurity(), empty());
assertThat(p.getMeta().getSecurity("foo", "bar"), nullValue());
assertThat(p.getMeta().getTag(), empty());
assertThat(p.getMeta().getTag("foo", "bar"), nullValue());
assertThat(p.getMeta().getVersionId(), nullValue());
}
@Test
public void testEncodeCompleteMetaLists() {
Patient p = new Patient();
p.getMeta().addProfile("http://foo/profile1");
p.getMeta().addProfile("http://foo/profile2");
p.getMeta().addSecurity().setSystem("SEC_S1").setCode("SEC_C1").setDisplay("SED_D1");
p.getMeta().addSecurity().setSystem("SEC_S2").setCode("SEC_C2").setDisplay("SED_D2");
p.getMeta().addTag().setSystem("TAG_S1").setCode("TAG_C1").setDisplay("TAG_D1");
p.getMeta().addTag().setSystem("TAG_S2").setCode("TAG_C2").setDisplay("TAG_D2");
String out = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(out);
//@formatter:off
assertThat(out, stringContainsInOrder(
"<meta>",
"<profile value=\"http://foo/profile1\"/>",
"<profile value=\"http://foo/profile2\"/>",
"<security>",
"<system value=\"SEC_S1\"/>",
"<code value=\"SEC_C1\"/>",
"<display value=\"SED_D1\"/>",
"</security>",
"<security>",
"<system value=\"SEC_S2\"/>",
"<code value=\"SEC_C2\"/>",
"<display value=\"SED_D2\"/>",
"</security>",
"<tag>",
"<system value=\"TAG_S1\"/>",
"<display value=\"TAG_D1\"/>",
"</tag>",
"<tag>",
"<system value=\"TAG_S2\"/>",
"<display value=\"TAG_D2\"/>",
"</tag>",
"</meta>"));
//@formatter:on
}
@Test
public void testEncodeNormalType() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("1234");
patient.addName().addFamily("Rossi").addGiven("Mario");
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(patient);
ourLog.info(messageString);
assertThat(messageString, not(containsString("<profile")));
}
@Test
public void testEncodeWithCustomType() {
MyCustomPatient patient = new MyCustomPatient();
patient.addIdentifier().setSystem("urn:system").setValue("1234");
patient.addName().addFamily("Rossi").addGiven("Mario");
patient.setInsulinLevel(new QuantityDt());
patient.setGlucoseLevel(new QuantityDt());
patient.setHbA1c(new QuantityDt());
patient.setBloodPressure(new QuantityDt());
patient.setCholesterol(new QuantityDt());
patient.setWeight(new StringDt("80 kg"));
patient.setWeight(new StringDt("185 cm"));
patient.setCheckDates(new ArrayList<DateTimeDt>());
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(patient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"<meta>",
"<profile value=\"http://example.com/foo\"/>",
"</meta>"));
//@formatter:on
//@formatter:off
assertThat(messageString, not(stringContainsInOrder(
"<meta>",
"<profile value=\"http://example.com/foo\"", "/>",
"<profile value=\"http://example.com/foo\"/>",
"</meta>")));
//@formatter:on
}
@Test
public void testEncodeWithCustomTypeAndAutoInsertedProfile() {
MyCustomPatient patient = new MyCustomPatient();
patient.getMeta().addProfile("http://example.com/foo");
patient.getMeta().addProfile("http://example.com/bar");
patient.addIdentifier().setSystem("urn:system").setValue("1234");
patient.addName().addFamily("Rossi").addGiven("Mario");
patient.setInsulinLevel(new QuantityDt());
patient.setGlucoseLevel(new QuantityDt());
patient.setHbA1c(new QuantityDt());
patient.setBloodPressure(new QuantityDt());
patient.setCholesterol(new QuantityDt());
patient.setWeight(new StringDt("80 kg"));
patient.setWeight(new StringDt("185 cm"));
patient.setCheckDates(new ArrayList<DateTimeDt>());
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(patient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"<meta>",
"<profile value=\"http://example.com/foo\"/>",
"<profile value=\"http://example.com/bar\"/>",
"</meta>"));
//@formatter:on
//@formatter:off
assertThat(messageString, not(stringContainsInOrder(
"<meta>",
"<profile value=\"http://example.com/foo\"", "/>",
"<profile value=\"http://example.com/foo\"/>",
"</meta>")));
//@formatter:on
}
/**
* See #318
*/
@Test
public void testParseResourceWithContainedResourcesWithProfile() {
//@formatter:off
String input = "<MedicationOrder xmlns=\"http://hl7.org/fhir\">"
+ "<id value=\"44cfa24c-52e1-a8ff-8428-4e7ce1165460-local\"/> "
+ "<meta> "
+ "<profile value=\"http://fhir.something.com/StructureDefinition/our-medication-order\"/> "
+ "</meta> "
+ "<contained> "
+ "<Medication xmlns=\"http://hl7.org/fhir\"> "
+ "<id value=\"1\"/>"
+ "<meta> "
+ "<profile value=\"http://fhir.something.com/StructureDefinition/our-medication\"/> "
+ "</meta> "
+ "<code> "
+ "<text value=\"medication\"/> "
+ "</code> "
+ "</Medication> "
+ "</contained> "
+ "<medication> "
+ "<reference value=\"#1\"/> "
+ "</medication> "
+ "</MedicationOrder>";
//@formatter:on
FhirContext ctx = FhirContext.forDstu2();
ctx.setDefaultTypeForProfile("http://fhir.something.com/StructureDefinition/our-medication", MyMedication.class);
MedicationOrder mo = ctx.newXmlParser().parseResource(MedicationOrder.class, input);
assertEquals(MyMedication.class, mo.getContained().getContainedResources().get(0).getClass());
}
@ResourceDef(name = "Patient", profile = "http://example.com/foo")
public static class MyCustomPatient extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "bloodPressure") // once every 3 month. The average target is 130/80 mmHg or less
@Extension(url = "http://example.com/BloodPressure", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's blood pressure")
private QuantityDt myBloodPressure;
// Dates of periodic tests
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
@Description(shortDefinition = "Dates of periodic tests")
private List<DateTimeDt> myCheckDates;
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's cholesterol")
private QuantityDt myCholesterol;
@Child(name = "glucoseLevel") // fingerprick test
@Extension(url = "http://example.com/Glucose", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's blood glucose")
private QuantityDt myGlucoseLevel;
// Periodic Tests
@Child(name = "hbA1c") // once every 6 month. The average target is 53 mmol/mol (or 7%) or less.
@Extension(url = "http://example.com/HbA1c", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's glucose")
private QuantityDt myHbA1c;
@Child(name = "Height")
@Extension(url = "http://example.com/Height", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The patient's height in cm")
private StringDt myHeight;
@Child(name = "insulinLevel") // Normal range is [43,208] pmol/l
@Extension(url = "http://example.com/Insuline", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's insulin")
private QuantityDt myInsulinLevel;
// Other parameters
@Child(name = "weight")
@Extension(url = "http://example.com/Weight", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The patient's weight in Kg")
private StringDt myWeight;
public QuantityDt Cholesterol() {
if (myCholesterol == null) {
myCholesterol = new QuantityDt();
}
myCholesterol.getValue();
myCholesterol.getSystem();
myCholesterol.getCode();
return myCholesterol;
}
public QuantityDt getBloodPressure() {
if (myBloodPressure == null) {
myBloodPressure = new QuantityDt();
}
myBloodPressure.getValue();
myBloodPressure.getSystem();
myBloodPressure.getCode();
return myBloodPressure;
}
public List<DateTimeDt> getCheckDates() {
if (myCheckDates == null) {
myCheckDates = new ArrayList<DateTimeDt>();
}
return myCheckDates;
}
public QuantityDt getGlucoseLevel() {
if (myGlucoseLevel == null) {
myGlucoseLevel = new QuantityDt();
}
myGlucoseLevel.getValue();
myGlucoseLevel.getSystem();
myGlucoseLevel.getCode();
return myGlucoseLevel;
}
public QuantityDt getHbA1c() {
if (myHbA1c == null) {
myHbA1c = new QuantityDt();
}
myHbA1c.getValue();
myHbA1c.getSystem();
myHbA1c.getCode();
return myHbA1c;
}
public StringDt getHeight() {
if (myHeight == null) {
myHeight = new StringDt();
}
return myHeight;
}
public QuantityDt getInsulinLevel() {
if (myInsulinLevel == null) {
myInsulinLevel = new QuantityDt();
}
myInsulinLevel.getValue();
myInsulinLevel.getSystem();
myInsulinLevel.getCode();
return myInsulinLevel;
}
public StringDt getWeight() {
if (myWeight == null) {
myWeight = new StringDt();
}
return myWeight;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myInsulinLevel, myGlucoseLevel, myHbA1c, myBloodPressure, myCholesterol, myWeight, myHeight, myCheckDates);
}
public void setBloodPressure(QuantityDt bloodPressure) {
myBloodPressure = bloodPressure;
myBloodPressure.setValue(110);
myBloodPressure.setSystem("http://unitsofmeasure.org");
myBloodPressure.setCode("mmHg");
}
public void setCheckDates(List<DateTimeDt> theCheckDates) {
myCheckDates = theCheckDates;
myCheckDates.add(new DateTimeDt("2010-01-02"));
}
public void setCholesterol(QuantityDt cholesterol) {
myCholesterol = cholesterol;
myCholesterol.setValue(2);
myCholesterol.setSystem("http://unitsofmeasure.org");
myCholesterol.setCode("mmol/l");
}
public void setGlucoseLevel(QuantityDt glucoseLevel) {
myGlucoseLevel = glucoseLevel;
myGlucoseLevel.setValue(95);
myGlucoseLevel.setSystem("http://unitsofmeasure.org");
myGlucoseLevel.setCode("mg/dl");
}
public void setHbA1c(QuantityDt hba1c) {
myHbA1c = hba1c;
myHbA1c.setValue(48);
myHbA1c.setSystem("http://unitsofmeasure.org");
myHbA1c.setCode("mmol/mol");
}
public void setHeight(StringDt height) {
myHeight = height;
}
// Setter/Getter methods
public void setInsulinLevel(QuantityDt insulinLevel) {
myInsulinLevel = insulinLevel;
myInsulinLevel.setValue(125);
myInsulinLevel.setSystem("http://unitsofmeasure.org");
myInsulinLevel.setCode("pmol/l");
}
public void setWeight(StringDt weight) {
myWeight = weight;
}
}
@ResourceDef()
public static class MyMedication extends Medication {
private static final long serialVersionUID = 1L;
}
}