Support _has param in conditional URLs in JPA

This commit is contained in:
James Agnew 2016-09-08 13:14:15 -04:00
parent 202a1ea885
commit 6357c38180
10 changed files with 529 additions and 467 deletions

View File

@ -62,17 +62,12 @@ import ca.uhn.fhir.util.UrlUtil;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class MethodUtil { public class MethodUtil {
/** Non instantiable */
private MethodUtil() {
// nothing
}
private static final String LABEL = "label=\""; private static final String LABEL = "label=\"";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
private static final String SCHEME = "scheme=\"";
private static final Set<String> ourServletRequestTypes = new HashSet<String>(); private static final Set<String> ourServletRequestTypes = new HashSet<String>();
private static final Set<String> ourServletResponseTypes = new HashSet<String>(); private static final Set<String> ourServletResponseTypes = new HashSet<String>();
private static final String SCHEME = "scheme=\"";
static { static {
ourServletRequestTypes.add("javax.servlet.ServletRequest"); ourServletRequestTypes.add("javax.servlet.ServletRequest");
ourServletResponseTypes.add("javax.servlet.ServletResponse"); ourServletResponseTypes.add("javax.servlet.ServletResponse");
@ -80,6 +75,11 @@ public class MethodUtil {
ourServletResponseTypes.add("javax.servlet.http.HttpServletResponse"); ourServletResponseTypes.add("javax.servlet.http.HttpServletResponse");
} }
/** Non instantiable */
private MethodUtil() {
// nothing
}
static void addTagsToPostOrPut(FhirContext theContext, IBaseResource resource, BaseHttpClientInvocation retVal) { static void addTagsToPostOrPut(FhirContext theContext, IBaseResource resource, BaseHttpClientInvocation retVal) {
if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
@ -603,8 +603,17 @@ public class MethodUtil {
* This is a utility method intended provided to help the JPA module. * This is a utility method intended provided to help the JPA module.
*/ */
public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) { public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
RestSearchParameterTypeEnum paramType = theParamDef.getParamType();
return parseQueryParams(paramType, theUnqualifiedParamName, theParameters);
}
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RestSearchParameterTypeEnum paramType, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null; QueryParameterAndBinder binder = null;
switch (theParamDef.getParamType()) { switch (paramType) {
case COMPOSITE: case COMPOSITE:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
case DATE: case DATE:
@ -628,6 +637,9 @@ public class MethodUtil {
case URI: case URI:
binder = new QueryParameterAndBinder(UriAndListParam.class, Collections.<Class<? extends IQueryParameterType>> emptyList()); binder = new QueryParameterAndBinder(UriAndListParam.class, Collections.<Class<? extends IQueryParameterType>> emptyList());
break; break;
case HAS:
binder = new QueryParameterAndBinder(HasAndListParam.class, Collections.<Class<? extends IQueryParameterType>> emptyList());
break;
} }
return binder.parse(theUnqualifiedParamName, theParameters); return binder.parse(theUnqualifiedParamName, theParameters);

View File

@ -24,6 +24,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
/** /**
@ -64,7 +65,7 @@ public class HasParam extends BaseParam implements IQueryParameterType {
void doSetValueAsQueryToken(String theQualifier, String theValue) { void doSetValueAsQueryToken(String theQualifier, String theValue) {
String qualifier = defaultString(theQualifier); String qualifier = defaultString(theQualifier);
if (!qualifier.startsWith(":")) { if (!qualifier.startsWith(":")) {
throwInvalidSyntaxException("_has" + qualifier); throwInvalidSyntaxException(Constants.PARAM_HAS + qualifier);
} }
int colonIndex0 = qualifier.indexOf(':', 1); int colonIndex0 = qualifier.indexOf(':', 1);
validateColon(qualifier, colonIndex0); validateColon(qualifier, colonIndex0);

View File

@ -115,6 +115,7 @@ public class Constants {
public static final String PARAM_DELETE = "_delete"; public static final String PARAM_DELETE = "_delete";
public static final String PARAM_ELEMENTS = "_elements"; public static final String PARAM_ELEMENTS = "_elements";
public static final String PARAM_FORMAT = "_format"; public static final String PARAM_FORMAT = "_format";
public static final String PARAM_HAS = "_has";
public static final String PARAM_HISTORY = "_history"; public static final String PARAM_HISTORY = "_history";
public static final String PARAM_INCLUDE = "_include"; public static final String PARAM_INCLUDE = "_include";
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse"; public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
@ -157,8 +158,8 @@ public class Constants {
public static final int STATUS_HTTP_409_CONFLICT = 409; public static final int STATUS_HTTP_409_CONFLICT = 409;
public static final int STATUS_HTTP_410_GONE = 410; public static final int STATUS_HTTP_410_GONE = 410;
public static final int STATUS_HTTP_412_PRECONDITION_FAILED = 412; public static final int STATUS_HTTP_412_PRECONDITION_FAILED = 412;
public static final int STATUS_HTTP_422_UNPROCESSABLE_ENTITY = 422;
public static final int STATUS_HTTP_422_UNPROCESSABLE_ENTITY = 422;
public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500; public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500;
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501; public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
public static final String TAG_SUBSETTED_CODE = "SUBSETTED"; public static final String TAG_SUBSETTED_CODE = "SUBSETTED";

View File

@ -130,13 +130,7 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.MethodUtil; import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.QualifiedParamList; import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriAndListParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -1467,14 +1461,23 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
} }
IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext()); IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
String firstMsg = null;
for (DeleteConflict next : theDeleteConflicts) { for (DeleteConflict next : theDeleteConflicts) {
String msg = "Unable to delete " + next.getTargetId().toUnqualifiedVersionless().getValue() StringBuilder b = new StringBuilder();
+ " because at least one resource has a reference to this resource. First reference found was resource " + next.getTargetId().toUnqualifiedVersionless().getValue() + " in path " b.append("Unable to delete ");
+ next.getSourcePath(); b.append(next.getTargetId().toUnqualifiedVersionless().getValue());
b.append(" because at least one resource has a reference to this resource. First reference found was resource ");
b.append(next.getTargetId().toUnqualifiedVersionless().getValue());
b.append(" in path ");
b.append(next.getSourcePath());
String msg = b.toString();
if (firstMsg == null) {
firstMsg = msg;
}
OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing"); OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing");
} }
throw new ResourceVersionConflictException("Delete failed because of constraint failure", oo); throw new ResourceVersionConflictException(firstMsg, oo);
} }
/** /**
@ -1694,6 +1697,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
continue; continue;
} }
if (Constants.PARAM_HAS.equals(nextParamName)) {
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(RestSearchParameterTypeEnum.HAS, nextParamName, paramList);
paramMap.add(nextParamName, param);
continue;
}
if (Constants.PARAM_COUNT.equals(nextParamName)) { if (Constants.PARAM_COUNT.equals(nextParamName)) {
if (paramList.size() > 0 && paramList.get(0).size() > 0) { if (paramList.size() > 0 && paramList.get(0).size() > 0) {
String intString = paramList.get(0).get(0); String intString = paramList.get(0).get(0);

View File

@ -295,7 +295,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
validateDeleteConflictsEmptyOrThrowException(deleteConflicts); validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
IBaseOperationOutcome oo; IBaseOperationOutcome oo;
if (deletedResources.isEmpty()) { if (deletedResources.isEmpty()) {
oo = OperationOutcomeUtil.newInstance(getContext()); oo = OperationOutcomeUtil.newInstance(getContext());

View File

@ -1917,7 +1917,7 @@ public class SearchBuilder {
addPredicateLanguage(nextParamEntry.getValue()); addPredicateLanguage(nextParamEntry.getValue());
} else if (nextParamName.equals("_has")) { } else if (nextParamName.equals(Constants.PARAM_HAS)) {
addPredicateHas(nextParamEntry.getValue(), theLastUpdated); addPredicateHas(nextParamEntry.getValue(), theLastUpdated);

View File

@ -23,39 +23,19 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType; import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.instance.model.api.*;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionDefinition;
@ -236,7 +216,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
return retVal; return retVal;
} }
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) { private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
RuntimeResourceDefinition resType; RuntimeResourceDefinition resType;
try { try {
@ -436,7 +415,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
DaoMethodOutcome outcome; DaoMethodOutcome outcome;
@ -463,7 +441,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
* end. * end.
*/ */
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext(); ) { for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext();) {
DeleteConflict next = iter.next(); DeleteConflict next = iter.next();
if (deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())) { if (deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())) {
iter.remove(); iter.remove();
@ -634,7 +612,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
} else { } else {
newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK)); newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
} }
newEntry.getResponse().setLastModified(((Resource)theRes).getMeta().getLastUpdated()); newEntry.getResponse().setLastModified(((Resource) theRes).getMeta().getLastUpdated());
} }
private static boolean isPlaceholder(IdType theId) { private static boolean isPlaceholder(IdType theId) {

View File

@ -8,6 +8,7 @@ import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@ -61,6 +62,7 @@ import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.NamingSystem; import org.hl7.fhir.dstu3.model.NamingSystem;
import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.OperationDefinition; import org.hl7.fhir.dstu3.model.OperationDefinition;
import org.hl7.fhir.dstu3.model.OperationOutcome; import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
@ -81,6 +83,7 @@ import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.valuesets.ObservationCategory;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@ -143,6 +146,35 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
} }
} }
@Test
public void testDeleteWithHas() {
Observation obs1 = new Observation();
obs1.setStatus(ObservationStatus.FINAL);
IIdType obs1id = myObservationDao.create(obs1).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.setStatus(ObservationStatus.FINAL);
IIdType obs2id = myObservationDao.create(obs2).getId().toUnqualifiedVersionless();
DiagnosticReport rpt = new DiagnosticReport();
rpt.addIdentifier().setSystem("foo").setValue("IDENTIFIER");
rpt.addResult(new Reference(obs2id));
IIdType rptId = myDiagnosticReportDao.create(rpt).getId().toUnqualifiedVersionless();
myObservationDao.read(obs1id);
myObservationDao.read(obs2id);
try {
myObservationDao.deleteByUrl("Observation?_has:DiagnosticReport:result:identifier=foo|IDENTIFIER", mySrd);
fail();
} catch (ResourceVersionConflictException e) {
assertThat(e.getMessage(), matchesPattern("Unable to delete Observation/[0-9]+ because at least one resource has a reference to this resource. First reference found was resource Observation/[0-9]+ in path DiagnosticReport.result"));
}
myObservationDao.read(obs1id);
myObservationDao.read(obs2id);
}
@Test @Test
public void testCodeSystemCreateAndDelete() { public void testCodeSystemCreateAndDelete() {
CodeSystem cs = new CodeSystem(); CodeSystem cs = new CodeSystem();

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.dstu3; package ca.uhn.fhir.jpa.dao.dstu3;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThan;
@ -27,25 +28,14 @@ import java.util.List;
import javax.mail.Quota.Resource; import javax.mail.Quota.Resource;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.Appointment; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryRequestComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryRequestComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType; import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationOrder;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After; import org.junit.After;
@ -68,10 +58,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -79,62 +66,9 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu3Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu3Test.class);
@AfterClass @After
public static void afterClassClearContext() { public void after() {
TestUtil.clearAllStaticFieldsForUnitTest(); myDaoConfig.setAllowInlineMatchUrlReferences(false);
}
/**
* See #410
*/
@Test
public void testContainedArePreservedForBug410() throws IOException {
String input = IOUtils.toString(getClass().getResourceAsStream("/bug-410-bundle.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle output = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
IdType id = new IdType(output.getEntry().get(1).getResponse().getLocation());
MedicationOrder mo = myMedicationOrderDao.read(id);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo));
}
@Test
public void testTransactionDoesNotAllowDanglingTemporaryIds() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
BundleEntryComponent entry = bundle.addEntry();
Patient p = new Patient();
p.getManagingOrganization().setReference("urn:uuid:30ce60cf-f7cb-4196-961f-cadafa8b7ff5");
entry.setResource(p);
entry.getRequest().setMethod(HTTPVerb.POST);
entry.getRequest().setUrl("Patient");
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (InvalidRequestException e) {
assertEquals("Unable to satisfy placeholder ID: urn:uuid:30ce60cf-f7cb-4196-961f-cadafa8b7ff5", e.getMessage());
}
}
@Test
public void testTransactionDoesNotLeavePlaceholderIds() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
mySystemDao.transaction(mySrd, bundle);
IBundleProvider history = mySystemDao.history(null, null, null);
Bundle list = toBundle(history);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(list));
assertEquals(6, list.getEntry().size());
Patient p = find(list, Patient.class, 0);
assertTrue(p.getIdElement().isIdPartValidLong());
assertTrue(p.getGeneralPractitionerFirstRep().getReferenceElement().isIdPartValidLong());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -153,88 +87,60 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
return null; return null;
} }
@Test
public void testTransactionFromBundle2() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/transaction-bundle.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle response = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response)); /**
assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus()); * See #410
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern("Practitioner/[0-9]+/_history/1"));
/*
* Now a second time
*/ */
@Test
public void testContainedArePreservedForBug410() throws IOException {
String input = IOUtils.toString(getClass().getResourceAsStream("/bug-410-bundle.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input); Bundle output = mySystemDao.transaction(mySrd, bundle);
response = mySystemDao.transaction(mySrd, bundle); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
assertEquals("200 OK", response.getEntry().get(0).getResponse().getStatus());
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern("Practitioner/[0-9]+/_history/1"));
IdType id = new IdType(output.getEntry().get(1).getResponse().getLocation());
MedicationOrder mo = myMedicationOrderDao.read(id);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo));
} }
@Test @Test
public void testTransactionWithNullReference() { public void testDeleteWithHas() {
Patient p = new Patient(); Observation obs1 = new Observation();
p.addName().addFamily("family"); obs1.setStatus(ObservationStatus.FINAL);
final IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); IIdType obs1id = myObservationDao.create(obs1).getId().toUnqualifiedVersionless();
Bundle inputBundle = new Bundle(); Observation obs2 = new Observation();
obs2.setStatus(ObservationStatus.FINAL);
IIdType obs2id = myObservationDao.create(obs2).getId().toUnqualifiedVersionless();
//@formatter:off DiagnosticReport rpt = new DiagnosticReport();
Patient app0 = new Patient(); rpt.addIdentifier().setSystem("foo").setValue("IDENTIFIER");
app0.addName().addFamily("NEW PATIENT"); rpt.addResult(new Reference(obs2id));
String placeholderId0 = IdDt.newRandomUuid().getValue(); IIdType rptId = myDiagnosticReportDao.create(rpt).getId().toUnqualifiedVersionless();
inputBundle
.addEntry()
.setResource(app0)
.setFullUrl(placeholderId0)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient");
//@formatter:on
//@formatter:off myObservationDao.read(obs1id);
Appointment app1 = new Appointment(); myObservationDao.read(obs2id);
app1.addParticipant().getActor().setReference(id.getValue());
inputBundle
.addEntry()
.setResource(app1)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Appointment");
//@formatter:on
//@formatter:off rpt = new DiagnosticReport();
Appointment app2 = new Appointment(); rpt.addIdentifier().setSystem("foo").setValue("IDENTIFIER");
app2.addParticipant().getActor().setDisplay("NO REF");
app2.addParticipant().getActor().setDisplay("YES REF").setReference(placeholderId0);
inputBundle
.addEntry()
.setResource(app2)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Appointment");
//@formatter:on
Bundle outputBundle = mySystemDao.transaction(mySrd, inputBundle); Bundle b = new Bundle();
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outputBundle)); b.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Observation?_has:DiagnosticReport:result:identifier=foo|IDENTIFIER");
b.addEntry().setResource(rpt).getRequest().setMethod(HTTPVerb.PUT).setUrl("DiagnosticReport?identifier=foo|IDENTIFIER");
mySystemDao.transaction(mySrd, b);
assertEquals(3, outputBundle.getEntry().size()); myObservationDao.read(obs1id);
IdDt id0 = new IdDt(outputBundle.getEntry().get(0).getResponse().getLocation()); try {
IdDt id2 = new IdDt(outputBundle.getEntry().get(2).getResponse().getLocation()); myObservationDao.read(obs2id);
fail();
app2 = myAppointmentDao.read(id2, mySrd); } catch (ResourceGoneException e) {
assertEquals("NO REF", app2.getParticipant().get(0).getActor().getDisplay()); // good
assertEquals(null, app2.getParticipant().get(0).getActor().getReference());
assertEquals("YES REF", app2.getParticipant().get(1).getActor().getDisplay());
assertEquals(id0.toUnqualifiedVersionless().getValue(), app2.getParticipant().get(1).getActor().getReference());
} }
rpt = myDiagnosticReportDao.read(rptId);
assertThat(rpt.getResult(), empty());
}
@Test @Test
public void testReindexing() { public void testReindexing() {
@ -431,108 +337,28 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
@Test
public void testTransactionWithInlineMatchUrl() throws Exception {
myDaoConfig.setAllowInlineMatchUrlReferences(true);
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle response = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
}
@Test @Test
public void testTransactionWithInlineMatchUrlMultipleMatches() throws Exception { public void testTransactionCreateInlineMatchUrlWithNoMatches() {
myDaoConfig.setAllowInlineMatchUrlReferences(true); String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (PreconditionFailedException e) {
assertEquals("Invalid match URL \"Patient?identifier=http://www.ghh.org/identifiers|condreftestpatid1\" - Multiple resources match this search", e.getMessage());
}
}
@Test
public void testTransactionWithInlineMatchUrlNoMatches() throws Exception {
myDaoConfig.setAllowInlineMatchUrlReferences(true);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (ResourceNotFoundException e) {
assertEquals("Invalid match URL \"Patient?identifier=http://www.ghh.org/identifiers|condreftestpatid1\" - No resources match this search", e.getMessage());
}
}
@Test
public void testTransactionCreateMatchUrlWithOneMatch() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Bundle request = new Bundle(); Bundle request = new Bundle();
Patient p = new Patient(); myDaoConfig.setAllowInlineMatchUrlReferences(true);
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation(); Observation o = new Observation();
o.getCode().setText("Some Observation"); o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName); o.getSubject().setReference("Patient?identifier=urn%3Asystem%7C" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
Bundle resp = mySystemDao.transaction(mySrd, request); try {
assertEquals(2, resp.getEntry().size()); mySystemDao.transaction(mySrd, request);
fail();
BundleEntryComponent respEntry = resp.getEntry().get(0); } catch (ResourceNotFoundException e) {
assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus()); assertEquals("Invalid match URL \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateInlineMatchUrlWithNoMatches\" - No resources match this search", e.getMessage());
assertThat(respEntry.getResponse().getLocation(), endsWith("Patient/" + id.getIdPart() + "/_history/1")); }
assertEquals("1", respEntry.getResponse().getEtag());
respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
o = (Observation) myObservationDao.read(new IdType(respEntry.getResponse().getLocationElement()), mySrd);
assertEquals(id.toVersionless().getValue(), o.getSubject().getReference());
assertEquals("1", o.getIdElement().getVersionIdPart());
} }
@After
public void after() {
myDaoConfig.setAllowInlineMatchUrlReferences(false);
}
@Test @Test
public void testTransactionCreateInlineMatchUrlWithOneMatch() { public void testTransactionCreateInlineMatchUrlWithOneMatch() {
@ -635,27 +461,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
@Test
public void testTransactionCreateInlineMatchUrlWithNoMatches() {
String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";
Bundle request = new Bundle();
myDaoConfig.setAllowInlineMatchUrlReferences(true);
Observation o = new Observation();
o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient?identifier=urn%3Asystem%7C" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
try {
mySystemDao.transaction(mySrd, request);
fail();
} catch (ResourceNotFoundException e) {
assertEquals("Invalid match URL \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateInlineMatchUrlWithNoMatches\" - No resources match this search", e.getMessage());
}
}
@Test @Test
public void testTransactionCreateInlineMatchUrlWithTwoMatches() { public void testTransactionCreateInlineMatchUrlWithTwoMatches() {
String methodName = "testTransactionCreateInlineMatchUrlWithTwoMatches"; String methodName = "testTransactionCreateInlineMatchUrlWithTwoMatches";
@ -684,6 +489,48 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
} }
@Test
public void testTransactionCreateMatchUrlWithOneMatch() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
Bundle resp = mySystemDao.transaction(mySrd, request);
assertEquals(2, resp.getEntry().size());
BundleEntryComponent respEntry = resp.getEntry().get(0);
assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), endsWith("Patient/" + id.getIdPart() + "/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
o = (Observation) myObservationDao.read(new IdType(respEntry.getResponse().getLocationElement()), mySrd);
assertEquals(id.toVersionless().getValue(), o.getSubject().getReference());
assertEquals("1", o.getIdElement().getVersionIdPart());
}
@Test @Test
public void testTransactionCreateMatchUrlWithTwoMatch() { public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch"; String methodName = "testTransactionCreateMatchUrlWithTwoMatch";
@ -836,49 +683,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
} }
@Test
public void testTransactionCreateWithPutUsingUrl() {
String methodName = "testTransactionCreateWithPutUsingUrl";
Bundle request = new Bundle();
request.setType(BundleType.TRANSACTION);
Observation o = new Observation();
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.PUT).setUrl("Observation/a" + methodName);
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.PUT).setUrl("Patient/" + methodName);
mySystemDao.transaction(mySrd, request);
myObservationDao.read(new IdType("Observation/a" + methodName), mySrd);
myPatientDao.read(new IdType("Patient/" + methodName), mySrd);
}
@Test
public void testTransactionCreateWithPutUsingAbsoluteUrl() {
String methodName = "testTransactionCreateWithPutUsingAbsoluteUrl";
Bundle request = new Bundle();
request.setType(BundleType.TRANSACTION);
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.PUT).setUrl("http://localhost/server/base/Patient/" + methodName);
mySystemDao.transaction(mySrd, request);
myPatientDao.read(new IdType("Patient/" + methodName), mySrd);
}
@Test
public void testTransactionCreateWithPutUsingUrl2() throws Exception {
String req = IOUtils.toString(FhirSystemDaoDstu3Test.class.getResourceAsStream("/bundle-dstu3.xml"), StandardCharsets.UTF_8);
Bundle request = myFhirCtx.newXmlParser().parseResource(Bundle.class, req);
mySystemDao.transaction(mySrd, request);
}
@Test @Test
public void testTransactionCreateWithInvalidMatchUrl() { public void testTransactionCreateWithInvalidMatchUrl() {
String methodName = "testTransactionCreateWithInvalidMatchUrl"; String methodName = "testTransactionCreateWithInvalidMatchUrl";
@ -952,6 +756,48 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
} }
@Test
public void testTransactionCreateWithPutUsingAbsoluteUrl() {
String methodName = "testTransactionCreateWithPutUsingAbsoluteUrl";
Bundle request = new Bundle();
request.setType(BundleType.TRANSACTION);
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.PUT).setUrl("http://localhost/server/base/Patient/" + methodName);
mySystemDao.transaction(mySrd, request);
myPatientDao.read(new IdType("Patient/" + methodName), mySrd);
}
@Test
public void testTransactionCreateWithPutUsingUrl() {
String methodName = "testTransactionCreateWithPutUsingUrl";
Bundle request = new Bundle();
request.setType(BundleType.TRANSACTION);
Observation o = new Observation();
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.PUT).setUrl("Observation/a" + methodName);
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.PUT).setUrl("Patient/" + methodName);
mySystemDao.transaction(mySrd, request);
myObservationDao.read(new IdType("Observation/a" + methodName), mySrd);
myPatientDao.read(new IdType("Patient/" + methodName), mySrd);
}
@Test
public void testTransactionCreateWithPutUsingUrl2() throws Exception {
String req = IOUtils.toString(FhirSystemDaoDstu3Test.class.getResourceAsStream("/bundle-dstu3.xml"), StandardCharsets.UTF_8);
Bundle request = myFhirCtx.newXmlParser().parseResource(Bundle.class, req);
mySystemDao.transaction(mySrd, request);
}
@Test @Test
public void testTransactionDeleteByResourceId() { public void testTransactionDeleteByResourceId() {
String methodName = "testTransactionDeleteByResourceId"; String methodName = "testTransactionDeleteByResourceId";
@ -1188,6 +1034,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
} }
@Test @Test
public void testTransactionDeleteMatchUrlWithZeroMatch() { public void testTransactionDeleteMatchUrlWithZeroMatch() {
String methodName = "testTransactionDeleteMatchUrlWithZeroMatch"; String methodName = "testTransactionDeleteMatchUrlWithZeroMatch";
@ -1232,6 +1079,43 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
} }
@Test
public void testTransactionDoesNotAllowDanglingTemporaryIds() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
BundleEntryComponent entry = bundle.addEntry();
Patient p = new Patient();
p.getManagingOrganization().setReference("urn:uuid:30ce60cf-f7cb-4196-961f-cadafa8b7ff5");
entry.setResource(p);
entry.getRequest().setMethod(HTTPVerb.POST);
entry.getRequest().setUrl("Patient");
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (InvalidRequestException e) {
assertEquals("Unable to satisfy placeholder ID: urn:uuid:30ce60cf-f7cb-4196-961f-cadafa8b7ff5", e.getMessage());
}
}
@Test
public void testTransactionDoesNotLeavePlaceholderIds() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
mySystemDao.transaction(mySrd, bundle);
IBundleProvider history = mySystemDao.history(null, null, null);
Bundle list = toBundle(history);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(list));
assertEquals(6, list.getEntry().size());
Patient p = find(list, Patient.class, 0);
assertTrue(p.getIdElement().isIdPartValidLong());
assertTrue(p.getGeneralPractitionerFirstRep().getReferenceElement().isIdPartValidLong());
}
@Test(expected = InvalidRequestException.class) @Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() { public void testTransactionFailsWithDuplicateIds() {
Bundle request = new Bundle(); Bundle request = new Bundle();
@ -1268,44 +1152,26 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
assertEquals("Patient/temp6789", p.getLink().get(0).getOther().getReference()); assertEquals("Patient/temp6789", p.getLink().get(0).getOther().getReference());
} }
/**
* Format changed, source isn't valid
*/
@Test @Test
@Ignore public void testTransactionFromBundle2() throws Exception {
public void testTransactionWithBundledValidationSourceAndTarget() throws Exception { String input = IOUtils.toString(getClass().getResourceAsStream("/transaction-bundle.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle response = mySystemDao.transaction(mySrd, bundle);
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/questionnaire-sdc-profile-example-ussg-fht.xml"); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
String bundleStr = IOUtils.toString(bundleRes, StandardCharsets.UTF_8); assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus());
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, bundleStr); assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern("Practitioner/[0-9]+/_history/1"));
Bundle resp = mySystemDao.transaction(mySrd, bundle);
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp);
ourLog.info(encoded);
encoded = myFhirCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(resp);
//@formatter:off
assertThat(encoded, containsString("\"response\":{" +
"\"status\":\"201 Created\"," +
"\"location\":\"Questionnaire/54127-6/_history/1\","));
//@formatter:on
/* /*
* Upload again to update * Now a second time
*/ */
resp = mySystemDao.transaction(mySrd, bundle); bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
response = mySystemDao.transaction(mySrd, bundle);
encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
ourLog.info(encoded); assertEquals("200 OK", response.getEntry().get(0).getResponse().getStatus());
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern("Practitioner/[0-9]+/_history/1"));
encoded = myFhirCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(resp);
//@formatter:off
assertThat(encoded, containsString("\"response\":{" +
"\"status\":\"200 OK\"," +
"\"location\":\"Questionnaire/54127-6/_history/2\","));
//@formatter:on
} }
@ -1367,6 +1233,25 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
private Bundle testTransactionOrderingCreateBundle(String methodName, int pass, IdType patientPlaceholderId) {
Bundle req = new Bundle();
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?identifier=" + methodName);
Observation obs = new Observation();
obs.getSubject().setReferenceElement(patientPlaceholderId);
obs.addIdentifier().setValue(methodName);
obs.getCode().setText(methodName + pass);
req.addEntry().setResource(obs).getRequest().setMethod(HTTPVerb.PUT).setUrl("Observation?identifier=" + methodName);
Patient pat = new Patient();
pat.addIdentifier().setValue(methodName);
pat.addName().addFamily(methodName + pass);
req.addEntry().setResource(pat).setFullUrl(patientPlaceholderId.getValue()).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
req.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Patient?identifier=" + methodName);
return req;
}
private void testTransactionOrderingValidateResponse(int pass, Bundle resp) { private void testTransactionOrderingValidateResponse(int pass, Bundle resp) {
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
assertEquals(4, resp.getEntry().size()); assertEquals(4, resp.getEntry().size());
@ -1395,25 +1280,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
assertThat(respGetBundle.getLink("self").getUrl(), endsWith("/Patient?identifier=testTransactionOrdering")); assertThat(respGetBundle.getLink("self").getUrl(), endsWith("/Patient?identifier=testTransactionOrdering"));
} }
private Bundle testTransactionOrderingCreateBundle(String methodName, int pass, IdType patientPlaceholderId) {
Bundle req = new Bundle();
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?identifier=" + methodName);
Observation obs = new Observation();
obs.getSubject().setReferenceElement(patientPlaceholderId);
obs.addIdentifier().setValue(methodName);
obs.getCode().setText(methodName + pass);
req.addEntry().setResource(obs).getRequest().setMethod(HTTPVerb.PUT).setUrl("Observation?identifier=" + methodName);
Patient pat = new Patient();
pat.addIdentifier().setValue(methodName);
pat.addName().addFamily(methodName + pass);
req.addEntry().setResource(pat).setFullUrl(patientPlaceholderId.getValue()).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
req.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Patient?identifier=" + methodName);
return req;
}
@Test @Test
public void testTransactionReadAndSearch() { public void testTransactionReadAndSearch() {
String methodName = "testTransactionReadAndSearch"; String methodName = "testTransactionReadAndSearch";
@ -1746,6 +1612,103 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
/**
* Format changed, source isn't valid
*/
@Test
@Ignore
public void testTransactionWithBundledValidationSourceAndTarget() throws Exception {
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/questionnaire-sdc-profile-example-ussg-fht.xml");
String bundleStr = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, bundleStr);
Bundle resp = mySystemDao.transaction(mySrd, bundle);
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp);
ourLog.info(encoded);
encoded = myFhirCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(resp);
//@formatter:off
assertThat(encoded, containsString("\"response\":{" +
"\"status\":\"201 Created\"," +
"\"location\":\"Questionnaire/54127-6/_history/1\","));
//@formatter:on
/*
* Upload again to update
*/
resp = mySystemDao.transaction(mySrd, bundle);
encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp);
ourLog.info(encoded);
encoded = myFhirCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(resp);
//@formatter:off
assertThat(encoded, containsString("\"response\":{" +
"\"status\":\"200 OK\"," +
"\"location\":\"Questionnaire/54127-6/_history/2\","));
//@formatter:on
}
@Test
public void testTransactionWithInlineMatchUrl() throws Exception {
myDaoConfig.setAllowInlineMatchUrlReferences(true);
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle response = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
}
@Test
public void testTransactionWithInlineMatchUrlMultipleMatches() throws Exception {
myDaoConfig.setAllowInlineMatchUrlReferences(true);
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
patient = new Patient();
patient.addIdentifier().setSystem("http://www.ghh.org/identifiers").setValue("condreftestpatid1");
myPatientDao.create(patient, mySrd);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (PreconditionFailedException e) {
assertEquals("Invalid match URL \"Patient?identifier=http://www.ghh.org/identifiers|condreftestpatid1\" - Multiple resources match this search", e.getMessage());
}
}
@Test
public void testTransactionWithInlineMatchUrlNoMatches() throws Exception {
myDaoConfig.setAllowInlineMatchUrlReferences(true);
String input = IOUtils.toString(getClass().getResourceAsStream("/simone-conditional-url.xml"), StandardCharsets.UTF_8);
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
try {
mySystemDao.transaction(mySrd, bundle);
fail();
} catch (ResourceNotFoundException e) {
assertEquals("Invalid match URL \"Patient?identifier=http://www.ghh.org/identifiers|condreftestpatid1\" - No resources match this search", e.getMessage());
}
}
@Test @Test
public void testTransactionWithInvalidType() { public void testTransactionWithInvalidType() {
Bundle request = new Bundle(); Bundle request = new Bundle();
@ -1762,6 +1725,64 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
@Test
public void testTransactionWithNullReference() {
Patient p = new Patient();
p.addName().addFamily("family");
final IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
Bundle inputBundle = new Bundle();
//@formatter:off
Patient app0 = new Patient();
app0.addName().addFamily("NEW PATIENT");
String placeholderId0 = IdDt.newRandomUuid().getValue();
inputBundle
.addEntry()
.setResource(app0)
.setFullUrl(placeholderId0)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient");
//@formatter:on
//@formatter:off
Appointment app1 = new Appointment();
app1.addParticipant().getActor().setReference(id.getValue());
inputBundle
.addEntry()
.setResource(app1)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Appointment");
//@formatter:on
//@formatter:off
Appointment app2 = new Appointment();
app2.addParticipant().getActor().setDisplay("NO REF");
app2.addParticipant().getActor().setDisplay("YES REF").setReference(placeholderId0);
inputBundle
.addEntry()
.setResource(app2)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Appointment");
//@formatter:on
Bundle outputBundle = mySystemDao.transaction(mySrd, inputBundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outputBundle));
assertEquals(3, outputBundle.getEntry().size());
IdDt id0 = new IdDt(outputBundle.getEntry().get(0).getResponse().getLocation());
IdDt id2 = new IdDt(outputBundle.getEntry().get(2).getResponse().getLocation());
app2 = myAppointmentDao.read(id2, mySrd);
assertEquals("NO REF", app2.getParticipant().get(0).getActor().getDisplay());
assertEquals(null, app2.getParticipant().get(0).getActor().getReference());
assertEquals("YES REF", app2.getParticipant().get(1).getActor().getDisplay());
assertEquals(id0.toUnqualifiedVersionless().getValue(), app2.getParticipant().get(1).getActor().getReference());
}
@Test @Test
public void testTransactionWithReferenceToCreateIfNoneExist() { public void testTransactionWithReferenceToCreateIfNoneExist() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
@ -1815,6 +1836,46 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
assertNotEquals(medOrderId1, medOrderId2); assertNotEquals(medOrderId1, medOrderId2);
} }
@Test
public void testTransactionWithRelativeOidIds() throws Exception {
Bundle res = new Bundle();
res.setType(BundleType.TRANSACTION);
Patient p1 = new Patient();
p1.setId("urn:oid:0.1.2.3");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds01");
res.addEntry().setResource(p1).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds02");
o1.setSubject(new Reference("urn:oid:0.1.2.3"));
res.addEntry().setResource(o1).getRequest().setMethod(HTTPVerb.POST).setUrl("Observation");
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds03");
o2.setSubject(new Reference("urn:oid:0.1.2.3"));
res.addEntry().setResource(o2).getRequest().setMethod(HTTPVerb.POST).setUrl("Observation");
Bundle resp = mySystemDao.transaction(mySrd, res);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
assertEquals(BundleType.TRANSACTIONRESPONSE, resp.getTypeElement().getValue());
assertEquals(3, resp.getEntry().size());
assertTrue(resp.getEntry().get(0).getResponse().getLocation(), new IdType(resp.getEntry().get(0).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
assertTrue(resp.getEntry().get(1).getResponse().getLocation(), new IdType(resp.getEntry().get(1).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
assertTrue(resp.getEntry().get(2).getResponse().getLocation(), new IdType(resp.getEntry().get(2).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
o1 = myObservationDao.read(new IdType(resp.getEntry().get(1).getResponse().getLocation()), mySrd);
o2 = myObservationDao.read(new IdType(resp.getEntry().get(2).getResponse().getLocation()), mySrd);
assertThat(o1.getSubject().getReferenceElement().getValue(), endsWith("Patient/" + p1.getIdElement().getIdPart()));
assertThat(o2.getSubject().getReferenceElement().getValue(), endsWith("Patient/" + p1.getIdElement().getIdPart()));
}
// //
// //
// /** // /**
@ -1917,46 +1978,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
// //
// } // }
@Test
public void testTransactionWithRelativeOidIds() throws Exception {
Bundle res = new Bundle();
res.setType(BundleType.TRANSACTION);
Patient p1 = new Patient();
p1.setId("urn:oid:0.1.2.3");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds01");
res.addEntry().setResource(p1).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds02");
o1.setSubject(new Reference("urn:oid:0.1.2.3"));
res.addEntry().setResource(o1).getRequest().setMethod(HTTPVerb.POST).setUrl("Observation");
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds03");
o2.setSubject(new Reference("urn:oid:0.1.2.3"));
res.addEntry().setResource(o2).getRequest().setMethod(HTTPVerb.POST).setUrl("Observation");
Bundle resp = mySystemDao.transaction(mySrd, res);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
assertEquals(BundleType.TRANSACTIONRESPONSE, resp.getTypeElement().getValue());
assertEquals(3, resp.getEntry().size());
assertTrue(resp.getEntry().get(0).getResponse().getLocation(), new IdType(resp.getEntry().get(0).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
assertTrue(resp.getEntry().get(1).getResponse().getLocation(), new IdType(resp.getEntry().get(1).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
assertTrue(resp.getEntry().get(2).getResponse().getLocation(), new IdType(resp.getEntry().get(2).getResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
o1 = myObservationDao.read(new IdType(resp.getEntry().get(1).getResponse().getLocation()), mySrd);
o2 = myObservationDao.read(new IdType(resp.getEntry().get(2).getResponse().getLocation()), mySrd);
assertThat(o1.getSubject().getReferenceElement().getValue(), endsWith("Patient/" + p1.getIdElement().getIdPart()));
assertThat(o2.getSubject().getReferenceElement().getValue(), endsWith("Patient/" + p1.getIdElement().getIdPart()));
}
/** /**
* This is not the correct way to do it, but we'll allow it to be lenient * This is not the correct way to do it, but we'll allow it to be lenient
*/ */
@ -2000,4 +2021,9 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
} }
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
} }

View File

@ -24,6 +24,10 @@
BanUnsupportedHttpMethodsInterceptor was erroring out when a client BanUnsupportedHttpMethodsInterceptor was erroring out when a client
attempts HTTP HEAD requests attempts HTTP HEAD requests
</action> </action>
<action type="fix">
Conditional URLs in JPA server (e.g. for delete or update) did not support the
<![CDATA[<code>_has</code>]]> parameter
</action>
</release> </release>
<release version="2.0" date="2016-08-30"> <release version="2.0" date="2016-08-30">
<action type="fix"> <action type="fix">