diff --git a/examples/src/main/java/example/RestfulPatientResourceProviderMore.java b/examples/src/main/java/example/RestfulPatientResourceProviderMore.java
index ce068006e7c..fb44a826950 100644
--- a/examples/src/main/java/example/RestfulPatientResourceProviderMore.java
+++ b/examples/src/main/java/example/RestfulPatientResourceProviderMore.java
@@ -71,6 +71,7 @@ import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
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.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
@@ -758,6 +759,23 @@ public MethodOutcome updatePatientConditional(
}
//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
@Update
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
index b2239eb88d4..ef885208efc 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
@@ -48,33 +48,33 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
int index = 0;
for (IParameter next : getParameters()) {
if (next instanceof ResourceParameter) {
+ resourceParameter = (ResourceParameter) next;
+ if (resourceParameter.getMode() != ResourceParameter.Mode.RESOURCE) {
+ continue;
+ }
if (myResourceType != null) {
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();
- if (Modifier.isAbstract(myResourceType.getModifiers())) {
- myResourceType = providerResourceType;
- }
-
- myResourceName = theContext.getResourceDefinition(providerResourceType).getName();
myResourceParameterIndex = 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);
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());
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
index 474d340a625..c32af007c00 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
@@ -73,6 +73,7 @@ import ca.uhn.fhir.rest.param.NumberAndListParam;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
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.TokenAndListParam;
import ca.uhn.fhir.rest.param.TransactionParameter;
@@ -408,10 +409,17 @@ public class MethodUtil {
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
} 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());
}
- 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) {
param = new NullParameter();
} else if (nextAnnotation instanceof ServerBase) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
index 8d582153510..6d49477c35b 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
@@ -35,6 +35,7 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.Validate;
import org.apache.http.entity.ContentType;
import org.hl7.fhir.instance.model.api.IBaseBinary;
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.MethodUtil;
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.EncodingEnum;
import ca.uhn.fhir.rest.server.IResourceProvider;
@@ -59,11 +61,16 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class ResourceParameter implements IParameter {
private boolean myBinary;
+ private Mode myMode;
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;
myBinary = IBaseBinary.class.isAssignableFrom(theParameterType);
+ myMode = theMode;
Class extends IBaseResource> providerResourceType = null;
if (theProvider instanceof IResourceProvider) {
@@ -76,6 +83,10 @@ public class ResourceParameter implements IParameter {
}
+ public Mode getMode() {
+ return myMode;
+ }
+
public Class extends IBaseResource> getResourceType() {
return myResourceType;
}
@@ -93,9 +104,21 @@ public class ResourceParameter implements IParameter {
@Override
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) {
-
FhirContext ctx = theRequest.getServer().getFhirContext();
String ct = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
@@ -110,6 +133,29 @@ public class ResourceParameter implements IParameter {
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) {
FhirContext ctx = theRequest.getServer().getFhirContext();
@@ -175,27 +221,8 @@ public class ResourceParameter implements IParameter {
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 enum Mode{
+ BODY, ENCODING, RESOURCE
}
}
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java
index 99d15561c4d..f8b9afdcc4a 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.rest.server;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.StringReader;
@@ -20,6 +21,7 @@ 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;
@@ -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.Observation;
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.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
@@ -48,11 +51,21 @@ import ca.uhn.fhir.util.PortUtil;
*/
public class CreateTest {
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 int ourPort;
+
private static DiagnosticReportProvider ourReportProvider;
+
private static Server ourServer;
+ @Before()
+ public void before() {
+ ourLastResourceBody=null;
+ ourLastEncoding=null;
+ }
+
@Test
public void testCreate() throws Exception {
@@ -73,6 +86,34 @@ public class CreateTest {
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(ourLastResourceBody, stringContainsInOrder(""," getResourceType() {
+ return Observation.class;
+ }
+
+ }
+
public static class DiagnosticReportProvider implements IResourceProvider {
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() {
return myLastTags;
}
@@ -203,13 +289,6 @@ public class CreateTest {
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 {
+ @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
public Class extends IResource> getResourceType() {
return Patient.class;
}
+ }
+
+ public static class OrganizationProvider implements IResourceProvider {
+
@Create()
- public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
- IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
- if (thePatient.getId().isEmpty() == false) {
- id = thePatient.getId();
- }
- return new MethodOutcome(id.withVersion("002"));
+ public MethodOutcome create(@ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
+ ourLastResourceBody=theResourceBody;
+ ourLastEncoding=theEncoding;
+
+ return new MethodOutcome(new IdDt("001"));
}
- }
-
- @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
public Class extends IResource> getResourceType() {
- return Observation.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"));
+ return Organization.class;
}
}
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ValidateTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ValidateTest.java
new file mode 100644
index 00000000000..30e98522a33
--- /dev/null
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ValidateTest.java
@@ -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("", " 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;
+ }
+
+ }
+
+}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/InstanceValidator.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/InstanceValidator.java
deleted file mode 100644
index 97da2926ca2..00000000000
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/InstanceValidator.java
+++ /dev/null
@@ -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 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 results = v.validate(document, profile);
- return results;
- } catch (Exception e) {
- throw new InternalErrorException("Unexpected failure while validating resource", e);
- }
- }
-
-}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/StructureDefinitionValidator.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/StructureDefinitionValidator.java
new file mode 100644
index 00000000000..7456a69eb9e
--- /dev/null
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/StructureDefinitionValidator.java
@@ -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 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 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);
+ }
+
+ }
+
+}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/InstanceValidatorTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/InstanceValidatorTest.java
deleted file mode 100644
index e88eb3616e5..00000000000
--- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/InstanceValidatorTest.java
+++ /dev/null
@@ -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 = ""
- + ""
- + "";
-
- InstanceValidator val = new InstanceValidator(ourCtx);
- List output = val.validate(input, Patient.class);
- assertEquals(output.toString(), 0, output.size());
- }
-
- @Test
- public void testValidateXmlResourceBadAttributes() {
- String input = ""
- + ""
- + ""
- + "";
-
- InstanceValidator val = new InstanceValidator(ourCtx);
- List output = val.validate(input, Patient.class);
- assertEquals(output.toString(), 1, output.size());
- assertThat(output.toString(), containsString("/f:Patient/f:foo Element is unknown"));
- }
-
-}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/StructureDefinitionValidatorTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/StructureDefinitionValidatorTest.java
new file mode 100644
index 00000000000..59b432f5152
--- /dev/null
+++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/validation/StructureDefinitionValidatorTest.java
@@ -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 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 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 = ""
+ + ""
+ + "";
+
+ StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
+ List output = val.validate(input, EncodingEnum.XML, Patient.class);
+ assertEquals(output.toString(), 0, output.size());
+ }
+
+
+ @Test
+ public void testValidateXmlResourceBadAttributes() {
+ String input = ""
+ + ""
+ + ""
+ + "";
+
+ StructureDefinitionValidator val = new StructureDefinitionValidator(ourCtx);
+ List 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"));
+ }
+}
diff --git a/src/site/xdoc/doc_rest_operations.xml b/src/site/xdoc/doc_rest_operations.xml
index 83c25d4188c..c65e9b1e070 100644
--- a/src/site/xdoc/doc_rest_operations.xml
+++ b/src/site/xdoc/doc_rest_operations.xml
@@ -177,6 +177,24 @@
http://fhir.example.com/Patient?identifier=system%7C00001
+
+ Accessing The Raw Resource Payload
+
+ 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 @ResourceParam
of type
+ String
(to access the raw resource body) and/or
+ EncodingEnum
(to determine which encoding was used)
+
+
+ The following example shows how to use these additonal data elements.
+
+
+
+
+
+
+
@@ -339,6 +357,13 @@
http://fhir.example.com/Patient
If-None-Exist: Patient?identifier=system%7C0001
+ Accessing The Raw Resource Payload
+
+ The create operation also supports access to the raw payload,
+ using the same semantics as raw payload access
+ for the update operation.
+
+