Improve error messages for invalid validate request
This commit is contained in:
parent
a306e3136f
commit
f45ad117fe
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.model.api;
|
|||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
|
||||
public abstract class BaseIdentifiableElement extends BaseElement implements IIdentifiableElement {
|
||||
|
||||
|
@ -36,6 +37,7 @@ public abstract class BaseIdentifiableElement extends BaseElement implements IId
|
|||
* @deprecated Use {@link #getElementSpecificId()} instead. This method will be removed because it is easily
|
||||
* confused with other ID methods (such as patient#getIdentifier)
|
||||
*/
|
||||
@CoverageIgnore
|
||||
@Deprecated
|
||||
@Override
|
||||
public IdDt getId() {
|
||||
|
@ -55,6 +57,7 @@ public abstract class BaseIdentifiableElement extends BaseElement implements IId
|
|||
* @deprecated Use {@link #setElementSpecificId(String)} instead. This method will be removed because it is easily
|
||||
* confused with other ID methods (such as patient#getIdentifier)
|
||||
*/
|
||||
@CoverageIgnore
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setId(IdDt theId) {
|
||||
|
@ -69,27 +72,33 @@ public abstract class BaseIdentifiableElement extends BaseElement implements IId
|
|||
* @deprecated Use {@link #setElementSpecificId(String)} instead. This method will be removed because it is easily
|
||||
* confused with other ID methods (such as patient#getIdentifier)
|
||||
*/
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setId(String theId) {
|
||||
myElementSpecificId = theId;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
private static class LockedId extends IdDt {
|
||||
|
||||
@CoverageIgnore
|
||||
public LockedId() {
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
public LockedId(String theElementSpecificId) {
|
||||
super(theElementSpecificId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CoverageIgnore
|
||||
public IdDt setValue(String theValue) throws DataFormatException {
|
||||
throw new UnsupportedOperationException("Use IElement#setElementSpecificId(String) to set the element ID for an element");
|
||||
}
|
||||
|
||||
@Override
|
||||
@CoverageIgnore
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
throw new UnsupportedOperationException("Use IElement#setElementSpecificId(String) to set the element ID for an element");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package ca.uhn.fhir.rest.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -27,18 +31,41 @@ public enum ValidationModeEnum {
|
|||
/**
|
||||
* The server checks the content, and then checks that the content would be acceptable as a create (e.g. that the content would not validate any uniqueness constraints)
|
||||
*/
|
||||
CREATE,
|
||||
CREATE("create"),
|
||||
|
||||
/**
|
||||
* The server checks the content, and then checks that it would accept it as an update against the nominated specific resource (e.g. that there are no changes to immutable fields the server does not allow to change, and checking version integrity if appropriate)
|
||||
*/
|
||||
UPDATE,
|
||||
UPDATE("update"),
|
||||
|
||||
/**
|
||||
* The server ignores the content, and checks that the nominated resource is allowed to be deleted (e.g. checking referential integrity rules)
|
||||
*/
|
||||
DELETE;
|
||||
DELETE("delete");
|
||||
|
||||
private static HashMap<String, ValidationModeEnum> myCodeToValue;
|
||||
private String myCode;
|
||||
|
||||
static {
|
||||
myCodeToValue = new HashMap<String, ValidationModeEnum>();
|
||||
for (ValidationModeEnum next : values()) {
|
||||
myCodeToValue.put(next.getCode(), next);
|
||||
}
|
||||
}
|
||||
|
||||
public static ValidationModeEnum forCode(String theCode) {
|
||||
Validate.notBlank(theCode, "theCode must not be blank");
|
||||
return myCodeToValue.get(theCode);
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return myCode;
|
||||
}
|
||||
|
||||
private ValidationModeEnum(String theCode) {
|
||||
myCode = theCode;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean isEmpty() {
|
||||
// return false;
|
||||
|
|
|
@ -498,12 +498,20 @@ public class MethodUtil {
|
|||
param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, Constants.EXTOP_VALIDATE_MODE, 0, 1).setConverter(new IConverter() {
|
||||
@Override
|
||||
public Object incomingServer(Object theObject) {
|
||||
return ValidationModeEnum.valueOf(theObject.toString().toUpperCase());
|
||||
if (isNotBlank(theObject.toString())) {
|
||||
ValidationModeEnum retVal = ValidationModeEnum.forCode(theObject.toString());
|
||||
if (retVal == null) {
|
||||
OperationParameter.throwInvalidMode(theObject.toString());
|
||||
}
|
||||
return retVal;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object outgoingClient(Object theObject) {
|
||||
return new StringDt(((ValidationModeEnum)theObject).name().toLowerCase());
|
||||
return new StringDt(((ValidationModeEnum)theObject).getCode());
|
||||
}
|
||||
});
|
||||
} else if (nextAnnotation instanceof Validate.Profile) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -179,7 +181,7 @@ public class OperationParameter implements IParameter {
|
|||
*/
|
||||
isSearchParam &= typeIsConcrete && !IBase.class.isAssignableFrom(myParameterType);
|
||||
|
||||
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType) || String.class.equals(myParameterType) || isSearchParam;
|
||||
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType) || String.class.equals(myParameterType) || isSearchParam || ValidationModeEnum.class.equals(myParameterType);
|
||||
|
||||
/*
|
||||
* The parameter can be of type string for validation methods - This is a bit weird. See ValidateDstu2Test. We
|
||||
|
@ -291,7 +293,17 @@ public class OperationParameter implements IParameter {
|
|||
for (String next : paramValues) {
|
||||
matchingParamValues.add(next);
|
||||
}
|
||||
|
||||
} else if (ValidationModeEnum.class.equals(myParameterType)) {
|
||||
|
||||
if (isNotBlank(paramValues[0])) {
|
||||
ValidationModeEnum validationMode = ValidationModeEnum.forCode(paramValues[0]);
|
||||
if (validationMode != null) {
|
||||
matchingParamValues.add(validationMode);
|
||||
} else {
|
||||
throwInvalidMode(paramValues[0]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (String nextValue : paramValues) {
|
||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||
|
@ -374,6 +386,10 @@ public class OperationParameter implements IParameter {
|
|||
}
|
||||
}
|
||||
|
||||
public static void throwInvalidMode(String paramValues) {
|
||||
throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\"");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void tryToAddValues(List<IBase> theParamValues, List<Object> theMatchingParamValues) {
|
||||
for (Object nextValue : theParamValues) {
|
||||
|
@ -436,4 +452,5 @@ public class OperationParameter implements IParameter {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.List;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
|
||||
/**
|
||||
* Utility methods for working with {@link IBundleProvider}
|
||||
|
@ -33,6 +34,7 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
public class BundleProviders {
|
||||
|
||||
/** Non instantiable */
|
||||
@CoverageIgnore
|
||||
private BundleProviders() {
|
||||
//nothing
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hl7.fhir.dstu3.model.IdType;
|
|||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.Resource;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
|
@ -138,7 +139,7 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
IBaseParameters inputParameters;
|
||||
if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("url").setValue(new StringType(termUrl));
|
||||
p.addParameter().setName("url").setValue(new UriType(termUrl));
|
||||
p.addParameter().setName("localfile").setValue(new StringType(datafile));
|
||||
inputParameters = p;
|
||||
} else {
|
||||
|
@ -154,6 +155,7 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
.execute();
|
||||
|
||||
ourLog.info("Upload complete!");
|
||||
ourLog.info("Response:\n{}", ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1428,16 +1428,6 @@ public class SearchBuilder {
|
|||
return singleCode;
|
||||
}
|
||||
|
||||
private Set<String> toCodes(Set<TermConcept> theCodeConcepts) {
|
||||
HashSet<String> retVal = Sets.newHashSet();
|
||||
for (TermConcept next : theCodeConcepts) {
|
||||
if (isNotBlank(next.getCode())) {
|
||||
retVal.add(next.getCode());
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Predicate createResourceLinkPathPredicate(String theParamName, Root<? extends ResourceLink> from) {
|
||||
return createResourceLinkPathPredicate(myContext, theParamName, from, myResourceType);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,9 @@ public class FhirResourceDaoDstu3<T extends IAnyResource> extends BaseHapiFhirRe
|
|||
validator.registerValidatorModule(new IdChecker(theMode));
|
||||
|
||||
ValidationResult result;
|
||||
if (isNotBlank(theRawResource)) {
|
||||
if (theResource == null) {
|
||||
throw new InvalidRequestException("No resource supplied for $validate operation (resource is required unless mode is \"delete\")");
|
||||
} else if (isNotBlank(theRawResource)) {
|
||||
result = validator.validateWithResult(theRawResource);
|
||||
} else {
|
||||
result = validator.validateWithResult(theResource);
|
||||
|
|
|
@ -217,12 +217,13 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
}
|
||||
}
|
||||
|
||||
ourLog.info("Validating code system");
|
||||
ourLog.info("Validating all codes in CodeSystem for storage (this can take some time for large sets)");
|
||||
|
||||
// Validate the code system
|
||||
IdentityHashMap<TermConcept, Object> conceptsStack = new IdentityHashMap<TermConcept, Object>();
|
||||
int totalCodeCount = 0;
|
||||
for (TermConcept next : theCodeSystem.getConcepts()) {
|
||||
validateConceptForStorage(next, theCodeSystem, conceptsStack);
|
||||
totalCodeCount += validateConceptForStorage(next, theCodeSystem, conceptsStack);
|
||||
}
|
||||
|
||||
ourLog.info("Saving version");
|
||||
|
@ -234,7 +235,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
codeSystem.setCurrentVersion(theCodeSystem);
|
||||
myCodeSystemDao.save(codeSystem);
|
||||
|
||||
ourLog.info("Saving concepts...");
|
||||
ourLog.info("Saving {} concepts...", totalCodeCount);
|
||||
|
||||
conceptsStack = new IdentityHashMap<TermConcept, Object>();
|
||||
for (TermConcept next : theCodeSystem.getConcepts()) {
|
||||
|
@ -275,20 +276,24 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private void validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack) {
|
||||
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack) {
|
||||
ValidateUtil.isNotNullOrThrowInvalidRequest(theConcept.getCodeSystem() == theCodeSystem, "Codesystem contains a code which does not reference the codesystem");
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "Codesystem contains a code which does not reference the codesystem");
|
||||
|
||||
|
||||
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
|
||||
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
|
||||
}
|
||||
|
||||
int retVal = 1;
|
||||
for (TermConceptParentChildLink next : theConcept.getChildren()) {
|
||||
next.setCodeSystem(theCodeSystem);
|
||||
validateConceptForStorage(next.getChild(), theCodeSystem, theConceptsStack);
|
||||
retVal += validateConceptForStorage(next.getChild(), theCodeSystem, theConceptsStack);
|
||||
}
|
||||
|
||||
theConceptsStack.remove(theConcept);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public TermConcept findCode(String theCodeSystem, String theCode) {
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
@ -46,6 +47,7 @@ import org.apache.commons.csv.CSVParser;
|
|||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -68,20 +70,35 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
|
|||
@Autowired
|
||||
private IHapiTerminologySvc myTermSvc;
|
||||
|
||||
private void dropCircularRefs(TermConcept theConcept, HashSet<String> theChain) {
|
||||
private void dropCircularRefs(TermConcept theConcept, LinkedHashSet<String> theChain, Map<String, TermConcept> theCode2concept) {
|
||||
|
||||
theChain.add(theConcept.getCode());
|
||||
for (Iterator<TermConceptParentChildLink> childIter = theConcept.getChildren().iterator(); childIter.hasNext();) {
|
||||
TermConceptParentChildLink next = childIter.next();
|
||||
TermConcept nextChild = next.getChild();
|
||||
if (theChain.contains(nextChild.getCode())) {
|
||||
ourLog.info("Removing circular reference code {} from parent {}", nextChild.getCode(), theConcept.getCode());
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Removing circular reference code ");
|
||||
b.append(nextChild.getCode());
|
||||
b.append(" from parent ");
|
||||
b.append(nextChild.getCode());
|
||||
b.append(". Chain was: ");
|
||||
for (String nextInChain : theChain) {
|
||||
TermConcept nextCode = theCode2concept.get(nextInChain);
|
||||
b.append(nextCode.getCode());
|
||||
b.append('[');
|
||||
b.append(StringUtils.substring(nextCode.getDisplay(), 0, 20).replace("[", "").replace("]", "").trim());
|
||||
b.append("] ");
|
||||
}
|
||||
ourLog.info(b.toString(), theConcept.getCode());
|
||||
childIter.remove();
|
||||
} else {
|
||||
theChain.add(theConcept.getCode());
|
||||
dropCircularRefs(nextChild, theChain);
|
||||
theChain.remove(theConcept.getCode());
|
||||
dropCircularRefs(nextChild, theChain, theCode2concept);
|
||||
}
|
||||
}
|
||||
theChain.remove(theConcept.getCode());
|
||||
|
||||
}
|
||||
|
||||
private TermConcept getOrCreateConcept(TermCodeSystemVersion codeSystemVersion, Map<String, TermConcept> id2concept, String id) {
|
||||
|
@ -152,7 +169,7 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
|
|||
continue;
|
||||
}
|
||||
|
||||
ourLog.debug("Streaming ZIP entry {} into temporary file", nextEntry.getName());
|
||||
ourLog.info("Streaming ZIP entry {} into temporary file", nextEntry.getName());
|
||||
|
||||
File nextOutFile = File.createTempFile("hapi_fhir", ".csv");
|
||||
nextOutFile.deleteOnExit();
|
||||
|
@ -206,7 +223,7 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
|
|||
ourLog.info("Done loading SNOMED CT files - {} root codes, {} total codes", rootConcepts.size(), code2concept.size());
|
||||
|
||||
for (TermConcept next : rootConcepts.values()) {
|
||||
dropCircularRefs(next, new HashSet<String>());
|
||||
dropCircularRefs(next, new LinkedHashSet<String>(), code2concept);
|
||||
}
|
||||
|
||||
codeSystemVersion.getConcepts().addAll(rootConcepts.values());
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
|||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeType;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.Condition;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
|
@ -2693,6 +2694,46 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateBadInputViaPost() throws IOException {
|
||||
|
||||
Parameters input = new Parameters();
|
||||
input.addParameter().setName("mode").setValue(new CodeType("create"));
|
||||
|
||||
String inputStr = myFhirCtx.newXmlParser().encodeResourceToString(input);
|
||||
ourLog.info(inputStr);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient/$validate");
|
||||
post.setEntity(new StringEntity(inputStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent());
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("No resource supplied for $validate operation (resource is required unless mode is "delete")"));
|
||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateBadInputViaGet() throws IOException {
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$validate?mode=create");
|
||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent());
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("No resource supplied for $validate operation (resource is required unless mode is "delete")"));
|
||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateResourceWithId() throws IOException {
|
||||
|
||||
|
|
|
@ -150,6 +150,24 @@ public class OperationServerDstu2Test {
|
|||
assertThat(response, containsString("HTTP Method GET is not allowed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWrongParameterType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerDt(123));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(response, containsString("Request has parameter PARAM1 of type IntegerDt but method expects type StringDt"));
|
||||
ourLog.info(response);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstance() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
|
|
|
@ -200,6 +200,18 @@ public class SearchDstu2Test {
|
|||
assertThat(responseContent, containsString("SYSTEM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchMethodReturnsNull() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchReturnNull");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals("searchReturnNull", ourLastMethod);
|
||||
assertThat(responseContent, containsString("<total value=\"0\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByPostWithBodyAndUrlParams() throws Exception {
|
||||
HttpPost httpGet = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?_format=json");
|
||||
|
@ -513,6 +525,14 @@ public class SearchDstu2Test {
|
|||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
@Search(queryName="searchReturnNull")
|
||||
public List<Patient> searchNoList() {
|
||||
ourLastMethod = "searchReturnNull";
|
||||
return null;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
@Search()
|
||||
public List<Patient> searchQuantity(
|
||||
|
|
|
@ -0,0 +1,721 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
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.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Conformance;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestOperationComponent;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
import org.hl7.fhir.dstu3.model.Money;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition;
|
||||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.dstu3.model.UnsignedIntType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
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.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class OperationServerDstu3Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static IdType ourLastId;
|
||||
private static String ourLastMethod;
|
||||
private static StringType ourLastParam1;
|
||||
private static Patient ourLastParam2;
|
||||
private static List<StringType> ourLastParam3;
|
||||
private static Money ourLastParamMoney1;
|
||||
private static UnsignedIntType ourLastParamUnsignedInt1;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(OperationServerDstu3Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastParam1 = null;
|
||||
ourLastParam2 = null;
|
||||
ourLastParam3 = null;
|
||||
ourLastParamUnsignedInt1 = null;
|
||||
ourLastParamMoney1 = null;
|
||||
ourLastId = null;
|
||||
ourLastMethod = "";
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConformance() throws Exception {
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||
Conformance p = client.fetchConformance().ofType(Conformance.class).execute();
|
||||
List<ConformanceRestOperationComponent> ops = p.getRest().get(0).getOperation();
|
||||
assertThat(ops.size(), greaterThan(1));
|
||||
assertThat(ops.get(0).getDefinition().getReferenceElement().getValue(), startsWith("#"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingGet() throws Exception {
|
||||
|
||||
// Try with a GET
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertThat(response, startsWith("<Bundle"));
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingHapiClient() throws Exception {
|
||||
Parameters p = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort).operation().onInstance(new IdType("Patient/123")).named("$everything").withParameters(new Parameters()).execute();
|
||||
Bundle b = (Bundle) p.getParameterFirstRep().getResource();
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingPost() throws Exception {
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(new Parameters());
|
||||
|
||||
// Try with a POST
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertThat(response, startsWith("<Bundle"));
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationCantUseGetIfItIsntIdempotent() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("POST", status.getFirstHeader(Constants.HEADER_ALLOW).getValue());
|
||||
assertThat(response, containsString("HTTP Method GET is not allowed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWrongParameterType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType(123));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(response, containsString("Request has parameter PARAM1 of type IntegerType but method expects type StringType"));
|
||||
ourLog.info(response);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstance() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("123", ourLastId.getIdPart());
|
||||
assertEquals("$OP_INSTANCE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
|
||||
/*
|
||||
* Against type should fail
|
||||
*/
|
||||
|
||||
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
status = ourClient.execute(httpPost);
|
||||
|
||||
response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(response);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstanceAndType_Instance() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE_OR_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("123", ourLastId.getIdPart());
|
||||
assertEquals("$OP_INSTANCE_OR_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstanceAndType_Type() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE_OR_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals(null, ourLastId);
|
||||
assertEquals("$OP_INSTANCE_OR_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnServer() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/$OP_SERVER");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_SERVER", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnTypeReturnBundle() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE_RET_BUNDLE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_TYPE_RET_BUNDLE", ourLastMethod);
|
||||
|
||||
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
assertEquals("100", resp.getEntryFirstRep().getResponse().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithBundleProviderResponse() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/$OP_INSTANCE_BUNDLE_PROVIDER?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(response);
|
||||
|
||||
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithGetUsingParams() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertNull(ourLastParam2);
|
||||
assertEquals("$OP_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithGetUsingParamsFailsWithNonPrimitive() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val&PARAM2=foo");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(405, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("POST", status.getFirstHeader(Constants.HEADER_ALLOW).getValue());
|
||||
assertThat(response, containsString("Can not invoke operation $OP_TYPE using HTTP GET because parameter PARAM2 is not a primitive datatype"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOperationWithListParam() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
p.addParameter().setName("PARAM3").setValue(new StringType("PARAM3val1"));
|
||||
p.addParameter().setName("PARAM3").setValue(new StringType("PARAM3val2"));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/$OP_SERVER_LIST_PARAM");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_SERVER_LIST_PARAM", ourLastMethod);
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals(null, ourLastParam1);
|
||||
assertEquals(2, ourLastParam3.size());
|
||||
assertEquals("PARAM3val1", ourLastParam3.get(0).getValue());
|
||||
assertEquals("PARAM3val2", ourLastParam3.get(1).getValue());
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeParams() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType("123"));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT", ourLastMethod);
|
||||
assertEquals("123", ourLastParamUnsignedInt1.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeParams2() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
Money money = new Money();
|
||||
money.setCode("CODE");
|
||||
money.setSystem("SYSTEM");
|
||||
money.setValue(123L);
|
||||
p.addParameter().setName("PARAM1").setValue(money);
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT2");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT2", ourLastMethod);
|
||||
assertEquals("CODE", ourLastParamMoney1.getCode());
|
||||
assertEquals("SYSTEM", ourLastParamMoney1.getSystem());
|
||||
assertEquals("123", ourLastParamMoney1.getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeUrl() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT?PARAM1=123");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT", ourLastMethod);
|
||||
assertEquals("123", ourLastParamUnsignedInt1.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWrongParamType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType("123"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(response);
|
||||
|
||||
assertThat(response, containsString("Request has parameter PARAM1 of type IntegerType but method expects type StringType"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWithOperations() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("read", ourLastMethod);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(2));
|
||||
|
||||
servlet.setFhirContext(ourCtx);
|
||||
servlet.setResourceProviders(new PatientProvider());
|
||||
servlet.setPlainProviders(new PlainProvider());
|
||||
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 void main(String[] theValue) {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("start").setValue(new DateTimeType("2001-01-02"));
|
||||
p.addParameter().setName("end").setValue(new DateTimeType("2015-07-10"));
|
||||
String inParamsStr = FhirContext.forDstu2().newXmlParser().encodeResourceToString(p);
|
||||
ourLog.info(inParamsStr.replace("\"", "\\\""));
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE")
|
||||
public Parameters opInstance(
|
||||
@IdParam IdType theId,
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_INSTANCE";
|
||||
ourLastId = theId;
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE_OR_TYPE")
|
||||
public Parameters opInstanceOrType(
|
||||
@IdParam(optional=true) IdType theId,
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_INSTANCE_OR_TYPE";
|
||||
ourLastId = theId;
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_PROFILE_DT2", idempotent=true)
|
||||
public Bundle opProfileType(
|
||||
@OperationParam(name="PARAM1") Money theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_PROFILE_DT2";
|
||||
ourLastParamMoney1 = theParam1;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_PROFILE_DT", idempotent=true)
|
||||
public Bundle opProfileType(
|
||||
@OperationParam(name="PARAM1") UnsignedIntType theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_PROFILE_DT";
|
||||
ourLastParamUnsignedInt1 = theParam1;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_TYPE", idempotent=true)
|
||||
public Parameters opType(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_TYPE_ONLY_STRING", idempotent=true)
|
||||
public Parameters opTypeOnlyString(
|
||||
@OperationParam(name="PARAM1") StringType theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE";
|
||||
ourLastParam1 = theParam1;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_TYPE_RET_BUNDLE")
|
||||
public Bundle opTypeRetBundle(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE_RET_BUNDLE";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Operation(name = "$everything", idempotent=true)
|
||||
public Bundle patientEverything(@IdParam IdType thePatientId) {
|
||||
ourLastMethod = "instance $everything";
|
||||
ourLastId = thePatientId;
|
||||
return new Bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just to make sure this method doesn't "steal" calls
|
||||
*/
|
||||
@Read
|
||||
public Patient read(@IdParam IdType theId) {
|
||||
ourLastMethod = "read";
|
||||
Patient retVal = new Patient();
|
||||
retVal.setId(theId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PlainProvider {
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE_BUNDLE_PROVIDER", idempotent=true)
|
||||
public IBundleProvider opInstanceReturnsBundleProvider() {
|
||||
ourLastMethod = "$OP_INSTANCE_BUNDLE_PROVIDER";
|
||||
|
||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||
for (int i =0; i < 100;i++) {
|
||||
Patient p = new Patient();
|
||||
p.setId("Patient/" + i);
|
||||
p.addName().addFamily("Patient " + i);
|
||||
resources.add(p);
|
||||
}
|
||||
|
||||
return new SimpleBundleProvider(resources);
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_SERVER")
|
||||
public Parameters opServer(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_SERVER";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_SERVER_LIST_PARAM")
|
||||
public Parameters opServerListParam(
|
||||
@OperationParam(name="PARAM2") Patient theParam2,
|
||||
@OperationParam(name="PARAM3") List<StringType> theParam3
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_SERVER_LIST_PARAM";
|
||||
ourLastParam2 = theParam2;
|
||||
ourLastParam3 = theParam3;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
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.hl7.fhir.dstu3.model.CodeType;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.Organization;
|
||||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
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.base.resource.BaseOperationOutcome;
|
||||
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.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ValidateDstu3Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static EncodingEnum ourLastEncoding;
|
||||
private static ValidationModeEnum ourLastMode;
|
||||
private static String ourLastProfile;
|
||||
private static String ourLastResourceBody;
|
||||
private static OperationOutcome ourOutcomeToReturn;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
public static Patient ourLastPatient;
|
||||
|
||||
@Before()
|
||||
public void before() {
|
||||
ourLastResourceBody = null;
|
||||
ourLastEncoding = null;
|
||||
ourOutcomeToReturn = null;
|
||||
ourLastMode = null;
|
||||
ourLastProfile = null;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidate() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(patient);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(resp, stringContainsInOrder("<OperationOutcome"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateInvalidMode() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(patient);
|
||||
params.addParameter().setName("mode").setValue(new CodeType("AAA"));
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(resp, stringContainsInOrder("Invalid mode value: "AAA""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateBlankMode() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(patient);
|
||||
params.addParameter().setName("mode").setValue(new CodeType(" "));
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateMissingResource() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("mode").setValue(new CodeType("create"));
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(null, ourLastPatient);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateWithNoParsed() throws Exception {
|
||||
|
||||
Organization org = new Organization();
|
||||
org.addIdentifier().setValue("001");
|
||||
org.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(org);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Organization/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(ourLastResourceBody, stringContainsInOrder("\"resourceType\":\"Organization\"", "\"identifier\"", "\"value\":\"001"));
|
||||
assertEquals(EncodingEnum.JSON, ourLastEncoding);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateWithOptions() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(patient);
|
||||
params.addParameter().setName("profile").setValue(new StringType("http://foo"));
|
||||
params.addParameter().setName("mode").setValue(new StringType(ValidationModeEnum.CREATE.name()));
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(resp, stringContainsInOrder("<OperationOutcome"));
|
||||
assertEquals("http://foo", ourLastProfile);
|
||||
assertEquals(ValidationModeEnum.CREATE, ourLastMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateWithResults() throws Exception {
|
||||
|
||||
ourOutcomeToReturn = new OperationOutcome();
|
||||
ourOutcomeToReturn.addIssue().setDiagnostics("FOOBAR");
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
Parameters params = new Parameters();
|
||||
params.addParameter().setName("resource").setResource(patient);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(resp, stringContainsInOrder("<OperationOutcome", "FOOBAR"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@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(ourCtx);
|
||||
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 OrganizationProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Organization> getResourceType() {
|
||||
return Organization.class;
|
||||
}
|
||||
|
||||
@Validate()
|
||||
public MethodOutcome validate(@ResourceParam String theResourceBody, @ResourceParam EncodingEnum theEncoding) {
|
||||
ourLastResourceBody = theResourceBody;
|
||||
ourLastEncoding = theEncoding;
|
||||
|
||||
return new MethodOutcome(new IdType("001"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Validate()
|
||||
public MethodOutcome validatePatient(@ResourceParam Patient thePatient, @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile) {
|
||||
|
||||
ourLastPatient = thePatient;
|
||||
IdType id;
|
||||
if (thePatient != null) {
|
||||
id = new IdType(thePatient.getIdentifier().get(0).getValue());
|
||||
if (thePatient.getIdElement().isEmpty() == false) {
|
||||
id = thePatient.getIdElement();
|
||||
}
|
||||
} else {
|
||||
id = new IdType("1");
|
||||
}
|
||||
ourLastMode = theMode;
|
||||
ourLastProfile = theProfile;
|
||||
|
||||
MethodOutcome outcome = new MethodOutcome(id.withVersion("002"));
|
||||
outcome.setOperationOutcome(ourOutcomeToReturn);
|
||||
return outcome;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -244,6 +244,10 @@
|
|||
DateTime parser incorrectly parsed times where more than 3 digits of
|
||||
precision were provided on the seconds after the decimal point
|
||||
</action>
|
||||
<action type="add">
|
||||
Improve error messages when the $validate operation is called but no resource
|
||||
is actually supplied to validate
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.5" date="2016-04-20">
|
||||
<action type="fix" issue="339">
|
||||
|
|
Loading…
Reference in New Issue