Correctly support _summary=search option

This commit is contained in:
James Agnew 2016-04-19 21:58:20 -04:00
parent 153c3ac5aa
commit 81fa46820a
13 changed files with 211 additions and 14 deletions

View File

@ -145,9 +145,6 @@ public abstract class BaseParser implements IParser {
/*
* There are lots of reasons we might skip encoding a particular child
*/
// if (myNext.getDef().getElementName().equals("extension") || myNext.getDef().getElementName().equals("modifierExtension")) {
// myNext = null;
// } else
if (myNext.getDef().getElementName().equals("id")) {
myNext = null;
} else if (!myNext.shouldBeEncoded()) {
@ -981,6 +978,12 @@ public abstract class BaseParser implements IParser {
}
if (myDef != null) {
if (myDef.getMin() > 0) {
if (theElements.contains("*.(mandatory)")) {
return true;
}
}
thePathBuilder.append('.');
thePathBuilder.append(myDef.getElementName());
return theElements.contains(thePathBuilder.toString());
@ -1016,6 +1019,12 @@ public abstract class BaseParser implements IParser {
retVal = !checkIfParentShouldNotBeEncodedAndBuildPath(new StringBuilder(), true);
}
}
// if (retVal == false && myEncodeElements.contains("*.(mandatory)")) {
// if (myDef.getMin() > 0) {
// retVal = true;
// }
// }
return retVal;
}
}

View File

@ -257,6 +257,7 @@ public interface IParser {
* <li><b>Patient.name.family</b> - Encode only the patient's family name</li>
* <li><b>*.text</b> - Encode the text element on any resource (only the very first position may contain a
* wildcard)</li>
* <li><b>*.(mandatory)</b> - This is a special case which causes any mandatory fields (min > 0) to be encoded</li>
* </ul>
*
* @param theEncodeElements

View File

@ -71,7 +71,7 @@ public class RestfulServerUtils {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServerUtils.class);
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<String>(Arrays.asList("Bundle", "*.text"));
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<String>(Arrays.asList("Bundle", "*.text", "*.(mandatory)"));
public static void configureResponseParser(RequestDetails theRequestDetails, IParser parser) {
// Pretty print

View File

@ -31,8 +31,8 @@ public class FhirResourceDaoBundleDstu2 extends FhirResourceDaoDstu2<Bundle> {
protected void preProcessResourceForStorage(Bundle theResource) {
super.preProcessResourceForStorage(theResource);
if (theResource.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT) {
String message = "Unable to store a Bundle resource on this server with a Bundle.type value other than '" + BundleTypeEnum.DOCUMENT.getCode() + "' - Value was: " + (theResource.getTypeElement().getValueAsEnum() != null ? theResource.getTypeElement().getValueAsEnum().getCode() : "(missing)");
if (theResource.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT && theResource.getTypeElement().getValueAsEnum() != BundleTypeEnum.COLLECTION) {
String message = "Unable to store a Bundle resource on this server with a Bundle.type of: " + (theResource.getTypeElement().getValueAsEnum() != null ? theResource.getTypeElement().getValueAsEnum().getCode() : "(missing)");
throw new UnprocessableEntityException(message);
}

View File

@ -32,8 +32,8 @@ public class FhirResourceDaoBundleDstu3 extends FhirResourceDaoDstu3<Bundle> {
protected void preProcessResourceForStorage(Bundle theResource) {
super.preProcessResourceForStorage(theResource);
if (theResource.getType() != BundleType.DOCUMENT) {
String message = "Unable to store a Bundle resource on this server with a Bundle.type value other than '" + BundleType.DOCUMENT.toCode() + "' - Value was: " + (theResource.getType() != null ? theResource.getType().toCode() : "(missing)");
if (theResource.getType() != BundleType.DOCUMENT && theResource.getType() != BundleType.COLLECTION) {
String message = "Unable to store a Bundle resource on this server with a Bundle.type value of: " + (theResource.getType() != null ? theResource.getType().toCode() : "(missing)");
throw new UnprocessableEntityException(message);
}

View File

@ -87,6 +87,9 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Qualifier("myConceptMapDaoDstu2")
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
@Autowired
@Qualifier("myBundleDaoDstu2")
protected IFhirResourceDao<Bundle> myBundleDao;
@Autowired
@Qualifier("myMedicationDaoDstu2")
protected IFhirResourceDao<Medication> myMedicationDao;
@Autowired

View File

@ -34,6 +34,7 @@ import java.util.Set;
import org.apache.commons.lang3.RandomStringUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
@ -73,6 +74,7 @@ import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueTypeEnum;
@ -106,7 +108,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
@SuppressWarnings("unchecked")
@ -129,6 +130,49 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
}
}
@Test
public void testCreateBundleAllowsDocumentAndCollection() {
String methodName = "testCreateBundleAllowsDocumentAndCollection";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType pid = myPatientDao.create(p, mySrd).getId();
p.setId(pid);
ourLog.info("Created patient, got it: {}", pid);
Bundle bundle = new Bundle();
bundle.setType((BundleTypeEnum)null);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
try {
myBundleDao.create(bundle, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: (missing)", e.getMessage());
}
bundle = new Bundle();
bundle.setType(BundleTypeEnum.BATCH_RESPONSE);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
try {
myBundleDao.create(bundle, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: batch-response", e.getMessage());
}
bundle = new Bundle();
bundle.setType(BundleTypeEnum.COLLECTION);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
myBundleDao.create(bundle, mySrd);
bundle = new Bundle();
bundle.setType(BundleTypeEnum.DOCUMENT);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
myBundleDao.create(bundle, mySrd);
}
/**
* This gets called from assertGone too! Careful about exceptions...
*/

View File

@ -93,6 +93,9 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
@Qualifier("myCodeSystemDaoDstu3")
protected IFhirResourceDao<CodeSystem> myCodeSystemDao;
@Autowired
@Qualifier("myBundleDaoDstu3")
protected IFhirResourceDao<Bundle> myBundleDao;
@Autowired
@Qualifier("myConceptMapDaoDstu3")
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
@Autowired

View File

@ -36,6 +36,7 @@ import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CodeableConcept;
@ -532,6 +533,48 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
}
}
@Test
public void testCreateBundleAllowsDocumentAndCollection() {
String methodName = "testCreateBundleAllowsDocumentAndCollection";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType pid = myPatientDao.create(p, mySrd).getId();
p.setId(pid);
ourLog.info("Created patient, got it: {}", pid);
Bundle bundle = new Bundle();
bundle.setType(null);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
try {
myBundleDao.create(bundle, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type value of: (missing)", e.getMessage());
}
bundle = new Bundle();
bundle.setType(BundleType.SEARCHSET);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
try {
myBundleDao.create(bundle, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type value of: searchset", e.getMessage());
}
bundle = new Bundle();
bundle.setType(BundleType.COLLECTION);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
myBundleDao.create(bundle, mySrd);
bundle = new Bundle();
bundle.setType(BundleType.DOCUMENT);
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
myBundleDao.create(bundle, mySrd);
}
@Test
public void testCreateWithIfNoneExistBasic() {
String methodName = "testCreateWithIfNoneExistBasic";

View File

@ -188,7 +188,9 @@
<baseResourceName>deviceusestatement</baseResourceName>
<baseResourceName>diagnosticorder</baseResourceName>
<baseResourceName>diagnosticreport</baseResourceName>
<!-- This is not a real resource
<baseResourceName>documentation</baseResourceName>
-->
<baseResourceName>documentmanifest</baseResourceName>
<baseResourceName>documentreference</baseResourceName>
<baseResourceName>eligibilityrequest</baseResourceName>

View File

@ -1475,6 +1475,30 @@ public class XmlParserDstu2Test {
}
@Test
public void testEncodeWithEncodeElementsMandatory() throws Exception {
MedicationOrder mo = new MedicationOrder();
mo.getText().setDiv("<div>DIV</div>");
mo.setNote("NOTE");
mo.setMedication(new ResourceReferenceDt("Medication/123"));
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
bundle.setTotal(100);
bundle.addEntry().setResource(mo);
{
IParser p = ourCtx.newXmlParser();
p.setEncodeElements(new HashSet<String>(Arrays.asList("Bundle.entry", "*.text", "*.(mandatory)")));
p.setPrettyPrint(true);
String out = p.encodeResourceToString(bundle);
ourLog.info(out);
assertThat(out, (containsString("DIV")));
assertThat(out, (containsString("Medication/123")));
assertThat(out, not(containsString("NOTE")));
}
}
@Test
public void testEncodeWithEncodeElements() throws Exception {
Patient patient = new Patient();

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -15,6 +16,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
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.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -22,6 +24,8 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum;
import ca.uhn.fhir.model.primitive.IdDt;
@ -79,11 +83,27 @@ public class SummaryParamTest {
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
assertThat(responseContent, not(containsString("<Bundle")));
assertThat(responseContent, not(containsString("<Patien")));
assertThat(responseContent, not(containsString("<Medic")));
assertEquals("<div>THE DIV</div>", responseContent);
assertThat(responseContent, not(containsString("efer")));
assertEquals(SummaryEnum.TEXT, ourLastSummary);
}
@Test
public void testReadSummaryTextWithMandatory() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationOrder/1?_summary=" + SummaryEnum.TEXT.getCode());
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
assertThat(responseContent, not(containsString("<Bundle")));
assertThat(responseContent, not(containsString("<Patien")));
assertEquals("<div>TEXT</div>", responseContent);
assertThat(responseContent, not(containsString("family")));
assertThat(responseContent, not(containsString("maritalStatus")));
assertEquals(SummaryEnum.TEXT, ourLastSummary);
}
@Test
@ -170,6 +190,22 @@ public class SummaryParamTest {
assertEquals(SummaryEnum.TEXT, ourLastSummary);
}
@Test
public void testSearchSummaryTextWithMandatory() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationOrder?_summary=" + SummaryEnum.TEXT.getCode() + "&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
assertThat(responseContent, (containsString("entry")));
assertThat(responseContent, (containsString(">TEXT<")));
assertThat(responseContent, (containsString("Medication/123")));
assertThat(responseContent, not(containsStringIgnoringCase("note")));
}
@Test
public void testSearchSummaryTextMulti() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=multi&_summary=" + SummaryEnum.TEXT.getCode());
@ -226,12 +262,10 @@ public class SummaryParamTest {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setResourceProviders(patientProvider);
servlet.setResourceProviders(new DummyPatientResourceProvider(), new DummyMedicationOrderProvider());
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
@ -244,6 +278,30 @@ public class SummaryParamTest {
}
public static class DummyMedicationOrderProvider implements IResourceProvider{
@Override
public Class<? extends IBaseResource> getResourceType() {
return MedicationOrder.class;
}
@Read
public MedicationOrder read(@IdParam IdDt theId) {
MedicationOrder retVal = new MedicationOrder();
retVal.getText().setDiv("<div>TEXT</div>");
retVal.getNoteElement().setValue("NOTE");
retVal.setMedication(new ResourceReferenceDt("Medication/123"));
retVal.setId(theId);
return retVal;
}
@Search
public List<MedicationOrder> read() {
return Arrays.asList(read(new IdDt("999")));
}
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override

View File

@ -426,6 +426,16 @@
Improve CLI error message if the tool can't bind to the requested port. Thanks
to Claude Nanjo for the suggestion!
</action>
<action type="fix">
Server param of <![CDATA[<code>_summary=text</code>]]> did not
include mandatory elements in return as well as
the text element, even though the FHIR specification
required it.
</action>
<action type="fix">
Remove invalid resource type "Documentation" from DSTU2
structures.
</action>
</release>
<release version="1.4" date="2016-02-04">
<action type="add">