Updates from DevDays

This commit is contained in:
James Agnew 2015-11-23 06:13:02 -05:00
parent c78be081ef
commit 1fe3bb9ff0
3 changed files with 130 additions and 96 deletions

View File

@ -16,8 +16,13 @@ import ca.uhn.fhir.util.ElementUtil;
/** /**
* Definition class for adding extensions to the built-in * Definition class for adding extensions to the built-in
* Patient resource type. * Patient resource type.
*
* Note the "profile" attribute below, which indicates the URL/ID of the
* profile implemented by this resource. You are not required to supply this,
* but if you do it will be automatically populated in the resource meta
* tag if the resource is returned by a server.
*/ */
@ResourceDef(name="Patient") @ResourceDef(name="Patient", profile="http://example.com/StructureDefinition/mypatient")
public class MyPatient extends Patient { public class MyPatient extends Patient {
/** /**

View File

@ -27,6 +27,7 @@ import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.io.Writer; import java.io.Writer;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
@ -52,6 +53,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
@ -59,6 +61,7 @@ import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
@ -79,16 +82,30 @@ public class RestfulServerUtils {
public static void addProfileToBundleEntry(FhirContext theContext, IBaseResource theResource, String theServerBase) { public static void addProfileToBundleEntry(FhirContext theContext, IBaseResource theResource, String theServerBase) {
if (theResource instanceof IResource) { if (theResource instanceof IResource) {
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) theResource); if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
if (tl == null) { List<IdDt> tl = ResourceMetadataKeyEnum.PROFILES.get((IResource) theResource);
tl = new TagList(); if (tl == null) {
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) theResource, tl); tl = new ArrayList<IdDt>();
} ResourceMetadataKeyEnum.PROFILES.put((IResource) theResource, tl);
}
RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(theResource); RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(theResource);
String profile = nextDef.getResourceProfile(theServerBase); String profile = nextDef.getResourceProfile(theServerBase);
if (isNotBlank(profile)) { if (isNotBlank(profile)) {
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null)); tl.add(new IdDt(profile));
}
} else {
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) theResource);
if (tl == null) {
tl = new TagList();
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) theResource, tl);
}
RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(theResource);
String profile = nextDef.getResourceProfile(theServerBase);
if (isNotBlank(profile)) {
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null));
}
} }
} }
} }
@ -133,7 +150,8 @@ public class RestfulServerUtils {
} }
} }
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint, BundleTypeEnum theBundleType) { public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
BundleTypeEnum theBundleType) {
try { try {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.append(theServerBase); b.append(theServerBase);
@ -223,8 +241,7 @@ public class RestfulServerUtils {
} }
/** /**
* Returns null if the request doesn't express that it wants FHIR. If it expresses that it wants * Returns null if the request doesn't express that it wants FHIR. If it expresses that it wants XML and JSON equally, returns thePrefer.
* XML and JSON equally, returns thePrefer.
*/ */
public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq, EncodingEnum thePrefer) { public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq, EncodingEnum thePrefer) {
String[] format = theReq.getParameterValues(Constants.PARAM_FORMAT); String[] format = theReq.getParameterValues(Constants.PARAM_FORMAT);
@ -289,7 +306,7 @@ public class RestfulServerUtils {
int equalsIndex = nextQualifier.indexOf('='); int equalsIndex = nextQualifier.indexOf('=');
if (equalsIndex != -1) { if (equalsIndex != -1) {
String nextQualifierKey = nextQualifier.substring(0, equalsIndex).trim(); String nextQualifierKey = nextQualifier.substring(0, equalsIndex).trim();
String nextQualifierValue = nextQualifier.substring(equalsIndex+1, nextQualifier.length()).trim(); String nextQualifierValue = nextQualifier.substring(equalsIndex + 1, nextQualifier.length()).trim();
if (nextQualifierKey.equals("q")) { if (nextQualifierKey.equals("q")) {
try { try {
q = Float.parseFloat(nextQualifierValue); q = Float.parseFloat(nextQualifierValue);
@ -311,43 +328,43 @@ public class RestfulServerUtils {
} }
// //
// //
// //
// //
// Matcher m = ACCEPT_HEADER_PATTERN.matcher(nextAcceptHeaderValue); // Matcher m = ACCEPT_HEADER_PATTERN.matcher(nextAcceptHeaderValue);
// float q = 1.0f; // float q = 1.0f;
// while (m.find()) { // while (m.find()) {
// String contentTypeGroup = m.group(1); // String contentTypeGroup = m.group(1);
// EncodingEnum encoding = Constants.FORMAT_VAL_TO_ENCODING.get(contentTypeGroup); // EncodingEnum encoding = Constants.FORMAT_VAL_TO_ENCODING.get(contentTypeGroup);
// if (encoding != null) { // if (encoding != null) {
// //
// String name = m.group(3); // String name = m.group(3);
// String value = m.group(4); // String value = m.group(4);
// if (name != null && value != null) { // if (name != null && value != null) {
// if ("q".equals(name)) { // if ("q".equals(name)) {
// try { // try {
// q = Float.parseFloat(value); // q = Float.parseFloat(value);
// q = Math.max(q, 0.0f); // q = Math.max(q, 0.0f);
// } catch (NumberFormatException e) { // } catch (NumberFormatException e) {
// ourLog.debug("Invalid Accept header q value: {}", value); // ourLog.debug("Invalid Accept header q value: {}", value);
// } // }
// } // }
// } // }
// } // }
// //
// if (encoding != null) { // if (encoding != null) {
// if (q > bestQ || (q == bestQ && encoding == thePrefer)) { // if (q > bestQ || (q == bestQ && encoding == thePrefer)) {
// retVal = encoding; // retVal = encoding;
// bestQ = q; // bestQ = q;
// } // }
// } // }
// //
// if (!",".equals(m.group(5))) { // if (!",".equals(m.group(5))) {
// break; // break;
// } // }
// } // }
// //
} }
return retVal; return retVal;
@ -546,7 +563,7 @@ public class RestfulServerUtils {
public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, String theServerBase, Set<SummaryEnum> theSummaryMode, boolean theRespondGzip, public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, String theServerBase, Set<SummaryEnum> theSummaryMode, boolean theRespondGzip,
boolean theRequestIsBrowser, RequestDetails theRequestDetails) throws IOException { boolean theRequestIsBrowser, RequestDetails theRequestDetails) throws IOException {
assert!theServerBase.endsWith("/"); assert !theServerBase.endsWith("/");
theHttpResponse.setStatus(200); theHttpResponse.setStatus(200);
@ -683,18 +700,18 @@ public class RestfulServerUtils {
} }
} }
// static Integer tryToExtractNamedParameter(HttpServletRequest theRequest, String name) { // static Integer tryToExtractNamedParameter(HttpServletRequest theRequest, String name) {
// String countString = theRequest.getParameter(name); // String countString = theRequest.getParameter(name);
// Integer count = null; // Integer count = null;
// if (isNotBlank(countString)) { // if (isNotBlank(countString)) {
// try { // try {
// count = Integer.parseInt(countString); // count = Integer.parseInt(countString);
// } catch (NumberFormatException e) { // } catch (NumberFormatException e) {
// ourLog.debug("Failed to parse _count value '{}': {}", countString, e); // ourLog.debug("Failed to parse _count value '{}': {}", countString, e);
// } // }
// } // }
// return count; // return count;
// } // }
public static void validateResourceListNotNull(List<? extends IBaseResource> theResourceList) { public static void validateResourceListNotNull(List<? extends IBaseResource> theResourceList) {
if (theResourceList == null) { if (theResourceList == null) {
@ -718,7 +735,7 @@ public class RestfulServerUtils {
try { try {
return Integer.parseInt(retVal[0]); return Integer.parseInt(retVal[0]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
ourLog.debug("Failed to parse {} value '{}': {}", new Object[] {theParamName, retVal[0], e}); ourLog.debug("Failed to parse {} value '{}': {}", new Object[] { theParamName, retVal[0], e });
return null; return null;
} }
} }

View File

@ -21,6 +21,7 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
@ -33,9 +34,28 @@ import ca.uhn.fhir.util.PortUtil;
public class ReadDstu2Test { public class ReadDstu2Test {
private static CloseableHttpClient ourClient; private static CloseableHttpClient ourClient;
private static int ourPort;
private static Server ourServer;
private static FhirContext ourCtx = FhirContext.forDstu2(); private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReadDstu2Test.class);
private static int ourPort;
private static Server ourServer;
/**
* In DSTU2+ the resource ID appears in the resource body
*/
@Test
public void testReadJson() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123?_format=json");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info(responseContent);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("p1ReadValue"));
assertThat(responseContent, containsString("p1ReadId"));
assertThat(responseContent, containsString("\"meta\":{\"profile\":[\"http://foo_profile\"]}"));
}
/** /**
* In DSTU2+ the resource ID appears in the resource body * In DSTU2+ the resource ID appears in the resource body
@ -52,21 +72,6 @@ public class ReadDstu2Test {
assertThat(responseContent, containsString("p1ReadId")); assertThat(responseContent, containsString("p1ReadId"));
} }
/**
* In DSTU2+ the resource ID appears in the resource body
*/
@Test
public void testReadJson() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123&_format=json");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("p1ReadValue"));
assertThat(responseContent, containsString("p1ReadId"));
}
@AfterClass @AfterClass
public static void afterClass() throws Exception { public static void afterClass() throws Exception {
ourServer.stop(); ourServer.stop();
@ -101,19 +106,26 @@ public class ReadDstu2Test {
*/ */
public static class DummyPatientResourceProvider implements IResourceProvider { public static class DummyPatientResourceProvider implements IResourceProvider {
@Read
public Patient read(@IdParam IdDt theId) {
Patient p1 = new Patient();
p1.setId("p1ReadId");
p1.addIdentifier().setValue("p1ReadValue");
return p1;
}
@Override @Override
public Class<? extends IResource> getResourceType() { public Class<? extends IResource> getResourceType() {
return Patient.class; return Patient.class;
} }
@Read
public Patient read(@IdParam IdDt theId) {
Patient p1 = new MyPatient();
p1.setId("p1ReadId");
p1.addIdentifier().setValue("p1ReadValue");
return p1;
}
}
@ResourceDef(name = "Patient", profile = "http://foo_profile")
public static class MyPatient extends Patient {
private static final long serialVersionUID = 1L;
} }
} }