Allow raw access to resource body in create/update/etc
This commit is contained in:
parent
064f113133
commit
e5b402cb14
|
@ -71,6 +71,7 @@ import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
|
@ -758,6 +759,23 @@ public MethodOutcome updatePatientConditional(
|
||||||
}
|
}
|
||||||
//END SNIPPET: updateConditional
|
//END SNIPPET: updateConditional
|
||||||
|
|
||||||
|
//START SNIPPET: updateRaw
|
||||||
|
@Update
|
||||||
|
public MethodOutcome updatePatientWithRawValue (
|
||||||
|
@ResourceParam Patient thePatient,
|
||||||
|
@IdParam IdDt theId,
|
||||||
|
@ResourceParam String theRawBody,
|
||||||
|
@ResourceParam EncodingEnum theEncodingEnum) {
|
||||||
|
|
||||||
|
// Here, thePatient will have the parsed patient body, but
|
||||||
|
// theRawBody will also have the raw text of the resource
|
||||||
|
// being created, and theEncodingEnum will tell you which
|
||||||
|
// encoding was used
|
||||||
|
|
||||||
|
return new MethodOutcome(); // populate this
|
||||||
|
}
|
||||||
|
//END SNIPPET: updateRaw
|
||||||
|
|
||||||
//START SNIPPET: update
|
//START SNIPPET: update
|
||||||
@Update
|
@Update
|
||||||
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
|
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
|
||||||
|
|
|
@ -48,33 +48,33 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (IParameter next : getParameters()) {
|
for (IParameter next : getParameters()) {
|
||||||
if (next instanceof ResourceParameter) {
|
if (next instanceof ResourceParameter) {
|
||||||
|
resourceParameter = (ResourceParameter) next;
|
||||||
|
if (resourceParameter.getMode() != ResourceParameter.Mode.RESOURCE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (myResourceType != null) {
|
if (myResourceType != null) {
|
||||||
throw new ConfigurationException("Method " + theMethod.getName() + " on type " + theMethod.getDeclaringClass() + " has more than one @ResourceParam. Only one is allowed.");
|
throw new ConfigurationException("Method " + theMethod.getName() + " on type " + theMethod.getDeclaringClass() + " has more than one @ResourceParam. Only one is allowed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceParameter = (ResourceParameter) next;
|
|
||||||
Class<? extends IBaseResource> providerResourceType = resourceParameter.getResourceType();
|
|
||||||
|
|
||||||
if (theProvider instanceof IResourceProvider) {
|
|
||||||
providerResourceType = ((IResourceProvider) theProvider).getResourceType();
|
|
||||||
}
|
|
||||||
|
|
||||||
myResourceType = resourceParameter.getResourceType();
|
myResourceType = resourceParameter.getResourceType();
|
||||||
if (Modifier.isAbstract(myResourceType.getModifiers())) {
|
|
||||||
myResourceType = providerResourceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
myResourceName = theContext.getResourceDefinition(providerResourceType).getName();
|
|
||||||
|
|
||||||
myResourceParameterIndex = index;
|
myResourceParameterIndex = index;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((myResourceType == null || Modifier.isAbstract(myResourceType.getModifiers())) && (theProvider instanceof IResourceProvider)) {
|
||||||
|
myResourceType = ((IResourceProvider) theProvider).getResourceType();
|
||||||
|
}
|
||||||
|
if (myResourceType == null) {
|
||||||
|
throw new ConfigurationException("Unable to determine resource type for method: " + theMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
myResourceName = theContext.getResourceDefinition(myResourceType).getName();
|
||||||
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod);
|
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod);
|
||||||
|
|
||||||
if (resourceParameter == null) {
|
if (resourceParameter == null) {
|
||||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @" + ResourceParam.class.getSimpleName());
|
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a resource parameter annotated with @" + ResourceParam.class.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ import ca.uhn.fhir.rest.param.NumberAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.QuantityAndListParam;
|
import ca.uhn.fhir.rest.param.QuantityAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.ResourceParameter;
|
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||||
|
import ca.uhn.fhir.rest.param.ResourceParameter.Mode;
|
||||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.TransactionParameter;
|
import ca.uhn.fhir.rest.param.TransactionParameter;
|
||||||
|
@ -408,10 +409,17 @@ public class MethodUtil {
|
||||||
|
|
||||||
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
|
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
|
||||||
} else if (nextAnnotation instanceof ResourceParam) {
|
} else if (nextAnnotation instanceof ResourceParam) {
|
||||||
if (!IResource.class.isAssignableFrom(parameterType)) {
|
Mode mode;
|
||||||
|
if (IBaseResource.class.isAssignableFrom(parameterType)) {
|
||||||
|
mode = Mode.RESOURCE;
|
||||||
|
} else if (String.class.equals(parameterType)) {
|
||||||
|
mode = ResourceParameter.Mode.BODY;
|
||||||
|
} else if (EncodingEnum.class.equals(parameterType)) {
|
||||||
|
mode = Mode.ENCODING;
|
||||||
|
} else {
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' is annotated with @" + ResourceParam.class.getSimpleName() + " but has a type that is not an implemtation of " + IResource.class.getCanonicalName());
|
throw new ConfigurationException("Method '" + theMethod.getName() + "' is annotated with @" + ResourceParam.class.getSimpleName() + " but has a type that is not an implemtation of " + IResource.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
param = new ResourceParameter((Class<? extends IResource>) parameterType, theProvider);
|
param = new ResourceParameter((Class<? extends IResource>) parameterType, theProvider, mode);
|
||||||
} else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {
|
} else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {
|
||||||
param = new NullParameter();
|
param = new NullParameter();
|
||||||
} else if (nextAnnotation instanceof ServerBase) {
|
} else if (nextAnnotation instanceof ServerBase) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -49,6 +50,7 @@ import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.IParameter;
|
import ca.uhn.fhir.rest.method.IParameter;
|
||||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||||
import ca.uhn.fhir.rest.method.Request;
|
import ca.uhn.fhir.rest.method.Request;
|
||||||
|
import ca.uhn.fhir.rest.param.ResourceParameter.Mode;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
@ -59,11 +61,16 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
public class ResourceParameter implements IParameter {
|
public class ResourceParameter implements IParameter {
|
||||||
|
|
||||||
private boolean myBinary;
|
private boolean myBinary;
|
||||||
|
private Mode myMode;
|
||||||
private Class<? extends IBaseResource> myResourceType;
|
private Class<? extends IBaseResource> myResourceType;
|
||||||
|
|
||||||
public ResourceParameter(Class<? extends IResource> theParameterType, Object theProvider) {
|
public ResourceParameter(Class<? extends IResource> theParameterType, Object theProvider, Mode theMode) {
|
||||||
|
Validate.notNull(theParameterType, "theParameterType can not be null");
|
||||||
|
Validate.notNull(theMode, "theMode can not be null");
|
||||||
|
|
||||||
myResourceType = theParameterType;
|
myResourceType = theParameterType;
|
||||||
myBinary = IBaseBinary.class.isAssignableFrom(theParameterType);
|
myBinary = IBaseBinary.class.isAssignableFrom(theParameterType);
|
||||||
|
myMode = theMode;
|
||||||
|
|
||||||
Class<? extends IBaseResource> providerResourceType = null;
|
Class<? extends IBaseResource> providerResourceType = null;
|
||||||
if (theProvider instanceof IResourceProvider) {
|
if (theProvider instanceof IResourceProvider) {
|
||||||
|
@ -76,6 +83,10 @@ public class ResourceParameter implements IParameter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Mode getMode() {
|
||||||
|
return myMode;
|
||||||
|
}
|
||||||
|
|
||||||
public Class<? extends IBaseResource> getResourceType() {
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
return myResourceType;
|
return myResourceType;
|
||||||
}
|
}
|
||||||
|
@ -93,9 +104,21 @@ public class ResourceParameter implements IParameter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object translateQueryParametersIntoServerArgument(Request theRequest, byte[] theRequestContents, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
public Object translateQueryParametersIntoServerArgument(Request theRequest, byte[] theRequestContents, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||||
|
switch (myMode) {
|
||||||
|
case BODY:
|
||||||
|
try {
|
||||||
|
return IOUtils.toString(createRequestReader(theRequest, theRequestContents));
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Shouldn't happen since we're reading from a byte array
|
||||||
|
throw new InternalErrorException("Failed to load request");
|
||||||
|
}
|
||||||
|
case ENCODING:
|
||||||
|
return RestfulServerUtils.determineRequestEncoding(theRequest);
|
||||||
|
case RESOURCE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (myBinary) {
|
if (myBinary) {
|
||||||
|
|
||||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||||
String ct = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
|
String ct = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
|
||||||
IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
|
IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
|
||||||
|
@ -110,6 +133,29 @@ public class ResourceParameter implements IParameter {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Reader createRequestReader(byte[] theRequestContents, Charset charset) {
|
||||||
|
Reader requestReader = new InputStreamReader(new ByteArrayInputStream(theRequestContents), charset);
|
||||||
|
return requestReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Reader createRequestReader(Request theRequest, byte[] theRequestContents) {
|
||||||
|
return createRequestReader(theRequestContents, determineRequestCharset(theRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Charset determineRequestCharset(Request theRequest) {
|
||||||
|
String ct = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
|
||||||
|
|
||||||
|
Charset charset = null;
|
||||||
|
if (isNotBlank(ct)) {
|
||||||
|
ContentType parsedCt = ContentType.parse(ct);
|
||||||
|
charset = parsedCt.getCharset();
|
||||||
|
}
|
||||||
|
if (charset == null) {
|
||||||
|
charset = Charset.forName("UTF-8");
|
||||||
|
}
|
||||||
|
return charset;
|
||||||
|
}
|
||||||
|
|
||||||
public static IBaseResource loadResourceFromRequest(Request theRequest, byte[] theRequestContents, BaseMethodBinding<?> theMethodBinding, Class<? extends IBaseResource> theResourceType) {
|
public static IBaseResource loadResourceFromRequest(Request theRequest, byte[] theRequestContents, BaseMethodBinding<?> theMethodBinding, Class<? extends IBaseResource> theResourceType) {
|
||||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||||
|
|
||||||
|
@ -175,27 +221,8 @@ public class ResourceParameter implements IParameter {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Reader createRequestReader(byte[] theRequestContents, Charset charset) {
|
public enum Mode{
|
||||||
Reader requestReader = new InputStreamReader(new ByteArrayInputStream(theRequestContents), charset);
|
BODY, ENCODING, RESOURCE
|
||||||
return requestReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Reader createRequestReader(Request theRequest, byte[] theRequestContents) {
|
|
||||||
return createRequestReader(theRequestContents, determineRequestCharset(theRequest));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Charset determineRequestCharset(Request theRequest) {
|
|
||||||
String ct = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
|
|
||||||
|
|
||||||
Charset charset = null;
|
|
||||||
if (isNotBlank(ct)) {
|
|
||||||
ContentType parsedCt = ContentType.parse(ct);
|
|
||||||
charset = parsedCt.getCharset();
|
|
||||||
}
|
|
||||||
if (charset == null) {
|
|
||||||
charset = Charset.forName("UTF-8");
|
|
||||||
}
|
|
||||||
return charset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
@ -20,6 +21,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hamcrest.core.StringContains;
|
import org.hamcrest.core.StringContains;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ import ca.uhn.fhir.model.dstu.resource.AdverseReaction;
|
||||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
@ -48,11 +51,21 @@ import ca.uhn.fhir.util.PortUtil;
|
||||||
*/
|
*/
|
||||||
public class CreateTest {
|
public class CreateTest {
|
||||||
private static CloseableHttpClient ourClient;
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static EncodingEnum ourLastEncoding;
|
||||||
|
private static String ourLastResourceBody;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateTest.class);
|
||||||
private static int ourPort;
|
private static int ourPort;
|
||||||
|
|
||||||
private static DiagnosticReportProvider ourReportProvider;
|
private static DiagnosticReportProvider ourReportProvider;
|
||||||
|
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
|
|
||||||
|
@Before()
|
||||||
|
public void before() {
|
||||||
|
ourLastResourceBody=null;
|
||||||
|
ourLastEncoding=null;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() throws Exception {
|
public void testCreate() throws Exception {
|
||||||
|
|
||||||
|
@ -73,6 +86,34 @@ public class CreateTest {
|
||||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), StringContains.containsString("UTF-8"));
|
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), StringContains.containsString("UTF-8"));
|
||||||
|
|
||||||
|
assertThat(ourLastResourceBody, stringContainsInOrder("<Patient ", "<identifier>","<value value=\"001"));
|
||||||
|
assertEquals(EncodingEnum.XML, ourLastEncoding);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateWithNoParsed() throws Exception {
|
||||||
|
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.addIdentifier().setValue("001");
|
||||||
|
org.addIdentifier().setValue("002");
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Organization");
|
||||||
|
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(org), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||||
|
|
||||||
|
HttpResponse status = ourClient.execute(httpPost);
|
||||||
|
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info("Response was:\n{}", responseContent);
|
||||||
|
|
||||||
|
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("http://localhost:" + ourPort + "/Organization/001", status.getFirstHeader("location").getValue());
|
||||||
|
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), StringContains.containsString("UTF-8"));
|
||||||
|
|
||||||
|
assertThat(ourLastResourceBody, stringContainsInOrder("\"resourceType\":\"Organization\"", "\"identifier\"","\"value\":\"001"));
|
||||||
|
assertEquals(EncodingEnum.JSON, ourLastEncoding);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -96,6 +137,27 @@ public class CreateTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCustomType() throws Exception {
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getIdentifier().setValue("001");
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
|
||||||
|
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(obs), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||||
|
|
||||||
|
HttpResponse status = ourClient.execute(httpPost);
|
||||||
|
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
|
||||||
|
ourLog.info("Response was:\n{}", responseContent);
|
||||||
|
|
||||||
|
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("http://localhost:" + ourPort + "/Observation/001/_history/002", status.getFirstHeader("location").getValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateJson() throws Exception {
|
public void testCreateJson() throws Exception {
|
||||||
|
|
||||||
|
@ -118,27 +180,6 @@ public class CreateTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateCustomType() throws Exception {
|
|
||||||
|
|
||||||
Observation obs = new Observation();
|
|
||||||
obs.getIdentifier().setValue("001");
|
|
||||||
|
|
||||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
|
|
||||||
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(obs), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
|
||||||
|
|
||||||
HttpResponse status = ourClient.execute(httpPost);
|
|
||||||
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
|
||||||
|
|
||||||
ourLog.info("Response was:\n{}", responseContent);
|
|
||||||
|
|
||||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
|
||||||
assertEquals("http://localhost:" + ourPort + "/Observation/001/_history/002", status.getFirstHeader("location").getValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateWithUnprocessableEntity() throws Exception {
|
public void testCreateWithUnprocessableEntity() throws Exception {
|
||||||
|
|
||||||
|
@ -178,7 +219,9 @@ public class CreateTest {
|
||||||
|
|
||||||
ServletHandler proxyHandler = new ServletHandler();
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
RestfulServer servlet = new RestfulServer();
|
RestfulServer servlet = new RestfulServer();
|
||||||
servlet.setResourceProviders(patientProvider, ourReportProvider, new DummyAdverseReactionResourceProvider(), new CustomObservationProvider());
|
servlet.setResourceProviders(
|
||||||
|
patientProvider, ourReportProvider, new DummyAdverseReactionResourceProvider(), new CustomObservationProvider(),
|
||||||
|
new OrganizationProvider());
|
||||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
ourServer.setHandler(proxyHandler);
|
ourServer.setHandler(proxyHandler);
|
||||||
|
@ -190,10 +233,53 @@ public class CreateTest {
|
||||||
ourClient = builder.build();
|
ourClient = builder.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ResourceDef(name = "Observation")
|
||||||
|
public static class CustomObservation extends Observation {
|
||||||
|
|
||||||
|
@Extension(url = "http://foo#string", definedLocally = false, isModifier = false)
|
||||||
|
@Child(name = "string")
|
||||||
|
private StringDt myString;
|
||||||
|
|
||||||
|
public StringDt getString() {
|
||||||
|
if (myString == null) {
|
||||||
|
myString = new StringDt();
|
||||||
|
}
|
||||||
|
return myString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString(StringDt theString) {
|
||||||
|
myString = theString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomObservationProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Create()
|
||||||
|
public MethodOutcome createPatient(@ResourceParam CustomObservation thePatient) {
|
||||||
|
IdDt id = new IdDt(thePatient.getIdentifier().getValue().getValue());
|
||||||
|
if (thePatient.getId().isEmpty() == false) {
|
||||||
|
id = thePatient.getId();
|
||||||
|
}
|
||||||
|
return new MethodOutcome(id.withVersion("002"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IResource> getResourceType() {
|
||||||
|
return Observation.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static class DiagnosticReportProvider implements IResourceProvider {
|
public static class DiagnosticReportProvider implements IResourceProvider {
|
||||||
private TagList myLastTags;
|
private TagList myLastTags;
|
||||||
|
|
||||||
|
@Create()
|
||||||
|
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
|
||||||
|
OperationOutcome outcome = new OperationOutcome();
|
||||||
|
outcome.addIssue().setDetails("FOOBAR");
|
||||||
|
throw new UnprocessableEntityException(outcome);
|
||||||
|
}
|
||||||
|
|
||||||
public TagList getLastTags() {
|
public TagList getLastTags() {
|
||||||
return myLastTags;
|
return myLastTags;
|
||||||
}
|
}
|
||||||
|
@ -203,13 +289,6 @@ public class CreateTest {
|
||||||
return DiagnosticReport.class;
|
return DiagnosticReport.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Create()
|
|
||||||
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
|
|
||||||
OperationOutcome outcome = new OperationOutcome();
|
|
||||||
outcome.addIssue().setDetails("FOOBAR");
|
|
||||||
throw new UnprocessableEntityException(outcome);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -252,55 +331,39 @@ public class CreateTest {
|
||||||
|
|
||||||
public static class PatientProvider implements IResourceProvider {
|
public static class PatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Create()
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
|
||||||
|
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||||
|
if (thePatient.getId().isEmpty() == false) {
|
||||||
|
id = thePatient.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLastResourceBody=theResourceBody;
|
||||||
|
ourLastEncoding=theEncoding;
|
||||||
|
|
||||||
|
return new MethodOutcome(id.withVersion("002"));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends IResource> getResourceType() {
|
public Class<? extends IResource> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OrganizationProvider implements IResourceProvider {
|
||||||
|
|
||||||
@Create()
|
@Create()
|
||||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
public MethodOutcome create(@ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
|
||||||
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
ourLastResourceBody=theResourceBody;
|
||||||
if (thePatient.getId().isEmpty() == false) {
|
ourLastEncoding=theEncoding;
|
||||||
id = thePatient.getId();
|
|
||||||
}
|
return new MethodOutcome(new IdDt("001"));
|
||||||
return new MethodOutcome(id.withVersion("002"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ResourceDef(name = "Observation")
|
|
||||||
public static class CustomObservation extends Observation {
|
|
||||||
|
|
||||||
@Extension(url = "http://foo#string", definedLocally = false, isModifier = false)
|
|
||||||
@Child(name = "string")
|
|
||||||
private StringDt myString;
|
|
||||||
|
|
||||||
public StringDt getString() {
|
|
||||||
if (myString == null) {
|
|
||||||
myString = new StringDt();
|
|
||||||
}
|
|
||||||
return myString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setString(StringDt theString) {
|
|
||||||
myString = theString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CustomObservationProvider implements IResourceProvider {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends IResource> getResourceType() {
|
public Class<? extends IResource> getResourceType() {
|
||||||
return Observation.class;
|
return Organization.class;
|
||||||
}
|
|
||||||
|
|
||||||
@Create()
|
|
||||||
public MethodOutcome createPatient(@ResourceParam CustomObservation thePatient) {
|
|
||||||
IdDt id = new IdDt(thePatient.getIdentifier().getValue().getValue());
|
|
||||||
if (thePatient.getId().isEmpty() == false) {
|
|
||||||
id = thePatient.getId();
|
|
||||||
}
|
|
||||||
return new MethodOutcome(id.withVersion("002"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
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.hamcrest.core.StringContains;
|
||||||
|
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.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Validate;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by dsotnikov on 2/25/2014.
|
||||||
|
*/
|
||||||
|
public class ValidateTest {
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static EncodingEnum ourLastEncoding;
|
||||||
|
private static String ourLastResourceBody;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateTest.class);
|
||||||
|
private static int ourPort;
|
||||||
|
private static Server ourServer;
|
||||||
|
|
||||||
|
@Before()
|
||||||
|
public void before() {
|
||||||
|
ourLastResourceBody = null;
|
||||||
|
ourLastEncoding = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidate() throws Exception {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setValue("001");
|
||||||
|
patient.addIdentifier().setValue("002");
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
|
||||||
|
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
|
||||||
|
HttpResponse status = ourClient.execute(httpPost);
|
||||||
|
|
||||||
|
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
|
assertThat(ourLastResourceBody, stringContainsInOrder("<Patient ", "<identifier>", "<value value=\"001"));
|
||||||
|
assertEquals(EncodingEnum.XML, ourLastEncoding);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateWithNoParsed() throws Exception {
|
||||||
|
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.addIdentifier().setValue("001");
|
||||||
|
org.addIdentifier().setValue("002");
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Organization/_validate");
|
||||||
|
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(org), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||||
|
|
||||||
|
HttpResponse status = ourClient.execute(httpPost);
|
||||||
|
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
|
assertThat(ourLastResourceBody, stringContainsInOrder("\"resourceType\":\"Organization\"", "\"identifier\"", "\"value\":\"001"));
|
||||||
|
assertEquals(EncodingEnum.JSON, ourLastEncoding);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws Exception {
|
||||||
|
ourPort = PortUtil.findFreePort();
|
||||||
|
ourServer = new Server(ourPort);
|
||||||
|
|
||||||
|
PatientProvider patientProvider = new PatientProvider();
|
||||||
|
|
||||||
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
|
RestfulServer servlet = new RestfulServer();
|
||||||
|
servlet.setResourceProviders(patientProvider, new OrganizationProvider());
|
||||||
|
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||||
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
ourServer.setHandler(proxyHandler);
|
||||||
|
ourServer.start();
|
||||||
|
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||||
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
|
builder.setConnectionManager(connectionManager);
|
||||||
|
ourClient = builder.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Validate()
|
||||||
|
public MethodOutcome validatePatient(@ResourceParam Patient thePatient, @ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
|
||||||
|
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||||
|
if (thePatient.getId().isEmpty() == false) {
|
||||||
|
id = thePatient.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLastResourceBody = theResourceBody;
|
||||||
|
ourLastEncoding = theEncoding;
|
||||||
|
|
||||||
|
return new MethodOutcome(id.withVersion("002"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OrganizationProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Validate()
|
||||||
|
public MethodOutcome validate(@ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
|
||||||
|
ourLastResourceBody = theResourceBody;
|
||||||
|
ourLastEncoding = theEncoding;
|
||||||
|
|
||||||
|
return new MethodOutcome(new IdDt("001"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IResource> getResourceType() {
|
||||||
|
return Organization.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,77 +0,0 @@
|
||||||
package ca.uhn.fhir.validation;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity;
|
|
||||||
import org.hl7.fhir.instance.model.StructureDefinition;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.utils.WorkerContext;
|
|
||||||
import org.hl7.fhir.instance.validation.ValidationMessage;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
|
|
||||||
public class InstanceValidator {
|
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(InstanceValidator.class);
|
|
||||||
|
|
||||||
private FhirContext myCtx;
|
|
||||||
private DocumentBuilderFactory myDocBuilderFactory;
|
|
||||||
|
|
||||||
InstanceValidator(FhirContext theContext) {
|
|
||||||
myCtx = theContext;
|
|
||||||
|
|
||||||
myDocBuilderFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
myDocBuilderFactory.setNamespaceAware(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ValidationMessage> validate(String theInput, Class<? extends IBaseResource> theResourceType) {
|
|
||||||
WorkerContext workerContext = new WorkerContext();
|
|
||||||
org.hl7.fhir.instance.validation.InstanceValidator v;
|
|
||||||
try {
|
|
||||||
v = new org.hl7.fhir.instance.validation.InstanceValidator(workerContext);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ConfigurationException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Document document;
|
|
||||||
try {
|
|
||||||
DocumentBuilder builder = myDocBuilderFactory.newDocumentBuilder();
|
|
||||||
InputSource src = new InputSource(new StringReader(theInput));
|
|
||||||
document = builder.parse(src);
|
|
||||||
} catch (Exception e2) {
|
|
||||||
ourLog.error("Failure to parse XML input", e2);
|
|
||||||
ValidationMessage m = new ValidationMessage();
|
|
||||||
m.setLevel(IssueSeverity.FATAL);
|
|
||||||
m.setMessage("Failed to parse input, it does not appear to be valid XML:" + e2.getMessage());
|
|
||||||
return Collections.singletonList(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
String profileCpName = "/org/hl7/fhir/instance/model/profile/" + myCtx.getResourceDefinition(theResourceType).getName().toLowerCase() + ".profile.xml";
|
|
||||||
String profileText;
|
|
||||||
try {
|
|
||||||
profileText = IOUtils.toString(InstanceValidator.class.getResourceAsStream(profileCpName), "UTF-8");
|
|
||||||
} catch (IOException e1) {
|
|
||||||
throw new ConfigurationException("Failed to load profile from classpath: " + profileCpName, e1);
|
|
||||||
}
|
|
||||||
StructureDefinition profile = myCtx.newXmlParser().parseResource(StructureDefinition.class, profileText);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<ValidationMessage> results = v.validate(document, profile);
|
|
||||||
return results;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity;
|
||||||
|
import org.hl7.fhir.instance.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.utils.WorkerContext;
|
||||||
|
import org.hl7.fhir.instance.validation.ValidationMessage;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
||||||
|
public class StructureDefinitionValidator {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StructureDefinitionValidator.class);
|
||||||
|
|
||||||
|
private FhirContext myCtx;
|
||||||
|
private DocumentBuilderFactory myDocBuilderFactory;
|
||||||
|
|
||||||
|
StructureDefinitionValidator(FhirContext theContext) {
|
||||||
|
myCtx = theContext;
|
||||||
|
|
||||||
|
myDocBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
myDocBuilderFactory.setNamespaceAware(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ValidationMessage> validate(String theInput, EncodingEnum theEncoding, Class<? extends IBaseResource> theResourceType) {
|
||||||
|
WorkerContext workerContext = new WorkerContext();
|
||||||
|
org.hl7.fhir.instance.validation.InstanceValidator v;
|
||||||
|
try {
|
||||||
|
v = new org.hl7.fhir.instance.validation.InstanceValidator(workerContext);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ConfigurationException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String profileCpName = "/org/hl7/fhir/instance/model/profile/" + myCtx.getResourceDefinition(theResourceType).getName().toLowerCase() + ".profile.xml";
|
||||||
|
String profileText;
|
||||||
|
try {
|
||||||
|
profileText = IOUtils.toString(StructureDefinitionValidator.class.getResourceAsStream(profileCpName), "UTF-8");
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new ConfigurationException("Failed to load profile from classpath: " + profileCpName, e1);
|
||||||
|
}
|
||||||
|
StructureDefinition profile = myCtx.newXmlParser().parseResource(StructureDefinition.class, profileText);
|
||||||
|
|
||||||
|
if (theEncoding == EncodingEnum.XML) {
|
||||||
|
Document document;
|
||||||
|
try {
|
||||||
|
DocumentBuilder builder = myDocBuilderFactory.newDocumentBuilder();
|
||||||
|
InputSource src = new InputSource(new StringReader(theInput));
|
||||||
|
document = builder.parse(src);
|
||||||
|
} catch (Exception e2) {
|
||||||
|
ourLog.error("Failure to parse XML input", e2);
|
||||||
|
ValidationMessage m = new ValidationMessage();
|
||||||
|
m.setLevel(IssueSeverity.FATAL);
|
||||||
|
m.setMessage("Failed to parse input, it does not appear to be valid XML:" + e2.getMessage());
|
||||||
|
return Collections.singletonList(m);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<ValidationMessage> results = v.validate(document, profile);
|
||||||
|
return results;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||||
|
}
|
||||||
|
} else if (theEncoding == EncodingEnum.JSON) {
|
||||||
|
Gson gson = new GsonBuilder().create();
|
||||||
|
JsonObject json = gson.fromJson(theInput, JsonObject.class);
|
||||||
|
try {
|
||||||
|
return v.validate(json, profile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown encoding: " + theEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package ca.uhn.fhir.validation;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.Patient;
|
|
||||||
import org.hl7.fhir.instance.validation.ValidationMessage;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
|
|
||||||
public class InstanceValidatorTest {
|
|
||||||
|
|
||||||
private static FhirContext ourCtx = FhirContext.forDstu2Hl7Org();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidateXmlResource() {
|
|
||||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">"
|
|
||||||
+ "<id value=\"123\"/>"
|
|
||||||
+ "</Patient>";
|
|
||||||
|
|
||||||
InstanceValidator val = new InstanceValidator(ourCtx);
|
|
||||||
List<ValidationMessage> output = val.validate(input, Patient.class);
|
|
||||||
assertEquals(output.toString(), 0, output.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidateXmlResourceBadAttributes() {
|
|
||||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\">"
|
|
||||||
+ "<id value=\"123\"/>"
|
|
||||||
+ "<foo value=\"222\"/>"
|
|
||||||
+ "</Patient>";
|
|
||||||
|
|
||||||
InstanceValidator val = new InstanceValidator(ourCtx);
|
|
||||||
List<ValidationMessage> output = val.validate(input, Patient.class);
|
|
||||||
assertEquals(output.toString(), 1, output.size());
|
|
||||||
assertThat(output.toString(), containsString("/f:Patient/f:foo Element is unknown"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.Patient;
|
||||||
|
import org.hl7.fhir.instance.validation.ValidationMessage;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
|
|
||||||
|
public class StructureDefinitionValidatorTest {
|
||||||
|
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu2Hl7Org();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateJsonResource() {
|
||||||
|
String input = "{"
|
||||||
|
+ "\"resourceType\":\"Patient\","
|
||||||
|
+ "\"id\":\"123\""
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
|
||||||
|
List<ValidationMessage> output = val.validate(input, EncodingEnum.JSON, Patient.class);
|
||||||
|
assertEquals(output.toString(), 0, output.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateJsonResourceBadAttributes() {
|
||||||
|
String input = "{"
|
||||||
|
+ "\"resourceType\":\"Patient\","
|
||||||
|
+ "\"id\":\"123\","
|
||||||
|
+ "\"foo\":\"123\""
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
|
||||||
|
StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
|
||||||
|
List<ValidationMessage> output = val.validate(input, EncodingEnum.JSON, Patient.class);
|
||||||
|
assertEquals(output.toString(), 1, output.size());
|
||||||
|
assertThat(output.toString(), containsString("/foo Element is unknown"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateXmlResource() {
|
||||||
|
String input = "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||||
|
+ "<id value=\"123\"/>"
|
||||||
|
+ "</Patient>";
|
||||||
|
|
||||||
|
StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
|
||||||
|
List<ValidationMessage> output = val.validate(input, EncodingEnum.XML, Patient.class);
|
||||||
|
assertEquals(output.toString(), 0, output.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateXmlResourceBadAttributes() {
|
||||||
|
String input = "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||||
|
+ "<id value=\"123\"/>"
|
||||||
|
+ "<foo value=\"222\"/>"
|
||||||
|
+ "</Patient>";
|
||||||
|
|
||||||
|
StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
|
||||||
|
List<ValidationMessage> output = val.validate(input, EncodingEnum.XML, Patient.class);
|
||||||
|
assertEquals(output.toString(), 1, output.size());
|
||||||
|
assertThat(output.toString(), containsString("/f:Patient/f:foo Element is unknown"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,6 +177,24 @@
|
||||||
<code>http://fhir.example.com/Patient?identifier=system%7C00001</code>
|
<code>http://fhir.example.com/Patient?identifier=system%7C00001</code>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<a name="raw_update_access"/>
|
||||||
|
<h4>Accessing The Raw Resource Payload</h4>
|
||||||
|
<p>
|
||||||
|
If you wish to have access to the raw resource payload as well as the parsed value
|
||||||
|
for any reason, you may also add parameters which have been annotated
|
||||||
|
with the <code>@ResourceParam</code> of type
|
||||||
|
<code>String</code> (to access the raw resource body) and/or
|
||||||
|
<code>EncodingEnum</code> (to determine which encoding was used)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The following example shows how to use these additonal data elements.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="updateRaw" />
|
||||||
|
<param name="file" value="examples/src/main/java/example/RestfulPatientResourceProviderMore.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
<a name="instance_delete" />
|
<a name="instance_delete" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -339,6 +357,13 @@
|
||||||
<code>http://fhir.example.com/Patient<br/>If-None-Exist: Patient?identifier=system%7C0001</code>
|
<code>http://fhir.example.com/Patient<br/>If-None-Exist: Patient?identifier=system%7C0001</code>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4>Accessing The Raw Resource Payload</h4>
|
||||||
|
<p>
|
||||||
|
The create operation also supports access to the raw payload,
|
||||||
|
using the same semantics as raw payload access
|
||||||
|
<a href="#raw_update_access">for the update operation</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<a name="type_search" />
|
<a name="type_search" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue