JPA server is now able to handle placeholder IDs (e.g. urn:uuid:00....000) being used in Bundle.entry.request.url as a part of the conditional URL within transactions.
This commit is contained in:
parent
2e60ff7521
commit
b13333c3c0
|
@ -63,6 +63,7 @@ import ca.uhn.fhir.util.UrlUtil;
|
|||
import ca.uhn.fhir.util.UrlUtil.UrlParts;
|
||||
|
||||
public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu3.class);
|
||||
|
||||
@Autowired
|
||||
|
@ -136,115 +137,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
return resp;
|
||||
}
|
||||
|
||||
private String extractTransactionUrlOrThrowException(BundleEntryComponent nextEntry, HTTPVerb verb) {
|
||||
String url = nextEntry.getRequest().getUrl();
|
||||
if (isBlank(url)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name()));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called for nested bundles (e.g. if we received a transaction with an entry that
|
||||
* was a GET search, this method is called on the bundle for the search result, that will be placed in the
|
||||
* outer bundle). This method applies the _summary and _content parameters to the output of
|
||||
* that bundle.
|
||||
*
|
||||
* TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future.
|
||||
*/
|
||||
private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) {
|
||||
IParser p = getContext().newJsonParser();
|
||||
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
||||
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
|
||||
}
|
||||
|
||||
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IBaseResource> theClass) {
|
||||
IFhirResourceDao<? extends IBaseResource> retVal = getDao(theClass);
|
||||
if (retVal == null) {
|
||||
throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta metaGetOperation(RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
Meta retVal = toMeta(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected Meta toMeta(Collection<TagDefinition> tagDefinitions) {
|
||||
Meta retVal = new Meta();
|
||||
for (TagDefinition next : tagDefinitions) {
|
||||
switch (next.getTagType()) {
|
||||
case PROFILE:
|
||||
retVal.addProfile(next.getCode());
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
case TAG:
|
||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
||||
RuntimeResourceDefinition resType;
|
||||
try {
|
||||
resType = getContext().getResourceDefinition(theParts.getResourceType());
|
||||
} catch (DataFormatException e) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
IFhirResourceDao<? extends IBaseResource> dao = null;
|
||||
if (resType != null) {
|
||||
dao = getDao(resType.getImplementingClass());
|
||||
}
|
||||
if (dao == null) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
// if (theParts.getResourceId() == null && theParts.getParams() == null) {
|
||||
// String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
// throw new InvalidRequestException(msg);
|
||||
// }
|
||||
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Override
|
||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
||||
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
||||
}
|
||||
|
||||
String actionName = "Transaction";
|
||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
}
|
||||
|
||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||
try {
|
||||
return doTransaction(theRequestDetails, theRequest, theActionName);
|
||||
} finally {
|
||||
super.clearRequestAsProcessingSubRequest(theRequestDetails);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
BundleType transactionType = theRequest.getTypeElement().getValue();
|
||||
|
@ -299,7 +191,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
getEntries.add(theRequest.getEntry().get(i));
|
||||
}
|
||||
}
|
||||
Collections.sort(theRequest.getEntry(), new TransactionSorter());
|
||||
|
||||
Set<String> deletedResources = new HashSet<String>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
|
@ -307,17 +198,32 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
|
||||
List<BundleEntryComponent> entries = new ArrayList<BundleEntryComponent>(theRequest.getEntry());
|
||||
|
||||
/*
|
||||
* See FhirSystemDaoDstu3Test#testTransactionWithPlaceholderIdInMatchUrl
|
||||
* Basically if the resource has a match URL that references a placeholder,
|
||||
* we try to handle the resource with the placeholder first.
|
||||
*/
|
||||
Set<String> placeholderIds = new HashSet<String>();
|
||||
for (BundleEntryComponent nextEntry : entries) {
|
||||
if (isNotBlank(nextEntry.getFullUrl()) && nextEntry.getFullUrl().startsWith(IdType.URN_PREFIX)) {
|
||||
placeholderIds.add(nextEntry.getFullUrl());
|
||||
}
|
||||
}
|
||||
Collections.sort(entries, new TransactionSorter(placeholderIds));
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type
|
||||
* PUT, POST or DELETE
|
||||
*/
|
||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
|
||||
if (i % 100 == 0) {
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, theRequest.getEntry().size());
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, entries.size());
|
||||
}
|
||||
|
||||
BundleEntryComponent nextReqEntry = theRequest.getEntry().get(i);
|
||||
BundleEntryComponent nextReqEntry = entries.get(i);
|
||||
Resource res = nextReqEntry.getResource();
|
||||
IdType nextResourceId = null;
|
||||
if (res != null) {
|
||||
|
@ -368,6 +274,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
res.setId((String) null);
|
||||
DaoMethodOutcome outcome;
|
||||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||
if (nextResourceId != null) {
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
|
@ -399,7 +306,9 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails);
|
||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||
for (ResourceTable deleted : allDeleted) {
|
||||
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless().getValueAsString());
|
||||
|
@ -430,6 +339,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
} else {
|
||||
res.setId((String) null);
|
||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
|
@ -607,6 +517,131 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
return response;
|
||||
}
|
||||
|
||||
private String extractTransactionUrlOrThrowException(BundleEntryComponent nextEntry, HTTPVerb verb) {
|
||||
String url = nextEntry.getRequest().getUrl();
|
||||
if (isBlank(url)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name()));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called for nested bundles (e.g. if we received a transaction with an entry that
|
||||
* was a GET search, this method is called on the bundle for the search result, that will be placed in the
|
||||
* outer bundle). This method applies the _summary and _content parameters to the output of
|
||||
* that bundle.
|
||||
*
|
||||
* TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future.
|
||||
*/
|
||||
private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) {
|
||||
IParser p = getContext().newJsonParser();
|
||||
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
||||
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
|
||||
}
|
||||
|
||||
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IBaseResource> theClass) {
|
||||
IFhirResourceDao<? extends IBaseResource> retVal = getDao(theClass);
|
||||
if (retVal == null) {
|
||||
throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta metaGetOperation(RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
Meta retVal = toMeta(tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||
String matchUrl = theMatchUrl;
|
||||
if (isNotBlank(matchUrl)) {
|
||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchUrl;
|
||||
}
|
||||
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
||||
RuntimeResourceDefinition resType;
|
||||
try {
|
||||
resType = getContext().getResourceDefinition(theParts.getResourceType());
|
||||
} catch (DataFormatException e) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
IFhirResourceDao<? extends IBaseResource> dao = null;
|
||||
if (resType != null) {
|
||||
dao = getDao(resType.getImplementingClass());
|
||||
}
|
||||
if (dao == null) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
// if (theParts.getResourceId() == null && theParts.getParams() == null) {
|
||||
// String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||
// throw new InvalidRequestException(msg);
|
||||
// }
|
||||
|
||||
return dao;
|
||||
}
|
||||
|
||||
protected Meta toMeta(Collection<TagDefinition> tagDefinitions) {
|
||||
Meta retVal = new Meta();
|
||||
for (TagDefinition next : tagDefinitions) {
|
||||
switch (next.getTagType()) {
|
||||
case PROFILE:
|
||||
retVal.addProfile(next.getCode());
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
case TAG:
|
||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Override
|
||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
||||
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
||||
}
|
||||
|
||||
String actionName = "Transaction";
|
||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
}
|
||||
|
||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||
try {
|
||||
return doTransaction(theRequestDetails, theRequest, theActionName);
|
||||
} finally {
|
||||
super.clearRequestAsProcessingSubRequest(theRequestDetails);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, IdType nextResourceId, DaoMethodOutcome outcome,
|
||||
BundleEntryComponent newEntry, String theResourceType, IBaseResource theRes, ServletRequestDetails theRequestDetails) {
|
||||
IdType newId = (IdType) outcome.getId().toUnqualifiedVersionless();
|
||||
|
@ -655,7 +690,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* Transaction Order, per the spec:
|
||||
*
|
||||
|
@ -664,37 +698,94 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
* Process any PUT interactions
|
||||
* Process any GET interactions
|
||||
*/
|
||||
//@formatter:off
|
||||
public class TransactionSorter implements Comparator<BundleEntryComponent> {
|
||||
|
||||
private Set<String> myPlaceholderIds;
|
||||
|
||||
public TransactionSorter(Set<String> thePlaceholderIds) {
|
||||
myPlaceholderIds = thePlaceholderIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(BundleEntryComponent theO1, BundleEntryComponent theO2) {
|
||||
public int compare(BundleEntryComponent theO1, BundleEntryComponent theO2) {
|
||||
int o1 = toOrder(theO1);
|
||||
int o2 = toOrder(theO2);
|
||||
|
||||
if (o1 == o2) {
|
||||
String matchUrl1 = toMatchUrl(theO1);
|
||||
String matchUrl2 = toMatchUrl(theO2);
|
||||
if (isBlank(matchUrl1) && isBlank(matchUrl2)) {
|
||||
return 0;
|
||||
}
|
||||
if (isBlank(matchUrl1)) {
|
||||
return -1;
|
||||
}
|
||||
if (isBlank(matchUrl2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
boolean match1containsSubstitutions = false;
|
||||
boolean match2containsSubstitutions = false;
|
||||
for (String nextPlaceholder : myPlaceholderIds) {
|
||||
if (matchUrl1.contains(nextPlaceholder)) {
|
||||
match1containsSubstitutions = true;
|
||||
}
|
||||
if (matchUrl2.contains(nextPlaceholder)) {
|
||||
match2containsSubstitutions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (match1containsSubstitutions && match2containsSubstitutions) {
|
||||
return 0;
|
||||
}
|
||||
if (!match1containsSubstitutions && !match2containsSubstitutions) {
|
||||
return 0;
|
||||
}
|
||||
if (match1containsSubstitutions) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return o1 - o2;
|
||||
}
|
||||
|
||||
private String toMatchUrl(BundleEntryComponent theEntry) {
|
||||
HTTPVerb verb = theEntry.getRequest().getMethod();
|
||||
if (verb == HTTPVerb.POST) {
|
||||
return theEntry.getRequest().getIfNoneExist();
|
||||
}
|
||||
if (verb == HTTPVerb.PUT || verb == HTTPVerb.DELETE) {
|
||||
String url = extractTransactionUrlOrThrowException(theEntry, verb);
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
if (isBlank(parts.getResourceId())) {
|
||||
return parts.getResourceType() + '?' + parts.getParams();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int toOrder(BundleEntryComponent theO1) {
|
||||
int o1 = 0;
|
||||
if (theO1.getRequest().getMethodElement().getValue() != null) {
|
||||
switch (theO1.getRequest().getMethodElement().getValue()) {
|
||||
case DELETE:
|
||||
o1 = 1;
|
||||
break;
|
||||
case POST:
|
||||
o1 = 2;
|
||||
break;
|
||||
case PUT:
|
||||
o1 = 3;
|
||||
break;
|
||||
case GET:
|
||||
o1 = 4;
|
||||
break;
|
||||
case NULL:
|
||||
o1 = 0;
|
||||
break;
|
||||
}
|
||||
switch (theO1.getRequest().getMethodElement().getValue()) {
|
||||
case DELETE:
|
||||
o1 = 1;
|
||||
break;
|
||||
case POST:
|
||||
o1 = 2;
|
||||
break;
|
||||
case PUT:
|
||||
o1 = 3;
|
||||
break;
|
||||
case GET:
|
||||
o1 = 4;
|
||||
break;
|
||||
case NULL:
|
||||
o1 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return o1;
|
||||
}
|
||||
|
|
|
@ -7,12 +7,21 @@ import static org.mockito.Mockito.times;
|
|||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
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.BundleEntryRequestComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -51,6 +60,100 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
private Bundle createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb theVerb) {
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat
|
||||
.addIdentifier()
|
||||
.setSystem("http://acme.org")
|
||||
.setValue("ID1");
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs
|
||||
.getCode()
|
||||
.addCoding()
|
||||
.setSystem("http://loinc.org")
|
||||
.setCode("29463-7");
|
||||
obs.setEffective(new DateTimeType("2011-09-03T11:13:00-04:00"));
|
||||
obs.setValue(new Quantity()
|
||||
.setValue(new BigDecimal("123.4"))
|
||||
.setCode("kg")
|
||||
.setSystem("http://unitsofmeasure.org")
|
||||
.setUnit("kg"));
|
||||
obs.getSubject().setReference("urn:uuid:0001");
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2
|
||||
.getCode()
|
||||
.addCoding()
|
||||
.setSystem("http://loinc.org")
|
||||
.setCode("29463-7");
|
||||
obs2.setEffective(new DateTimeType("2017-09-03T11:13:00-04:00"));
|
||||
obs2.setValue(new Quantity()
|
||||
.setValue(new BigDecimal("123.4"))
|
||||
.setCode("kg")
|
||||
.setSystem("http://unitsofmeasure.org")
|
||||
.setUnit("kg"));
|
||||
obs2.getSubject().setReference("urn:uuid:0001");
|
||||
|
||||
/*
|
||||
* Put one observation before the patient it references, and
|
||||
* one after it just to make sure that order doesn't matter
|
||||
*/
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
|
||||
if (theVerb == HTTPVerb.PUT) {
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0002")
|
||||
.setResource(obs)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Observation?subject=urn:uuid:0001&code=http%3A%2F%2Floinc.org|29463-7&date=2011-09-03T11:13:00-04:00");
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0001")
|
||||
.setResource(pat)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Patient?identifier=http%3A%2F%2Facme.org|ID1");
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0003")
|
||||
.setResource(obs2)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Observation?subject=urn:uuid:0001&code=http%3A%2F%2Floinc.org|29463-7&date=2017-09-03T11:13:00-04:00");
|
||||
} else if (theVerb == HTTPVerb.POST) {
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0002")
|
||||
.setResource(obs)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Observation")
|
||||
.setIfNoneExist("Observation?subject=urn:uuid:0001&code=http%3A%2F%2Floinc.org|29463-7&date=2011-09-03T11:13:00-04:00");
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0001")
|
||||
.setResource(pat)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Patient")
|
||||
.setIfNoneExist("Patient?identifier=http%3A%2F%2Facme.org|ID1");
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0003")
|
||||
.setResource(obs2)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Observation")
|
||||
.setIfNoneExist("Observation?subject=urn:uuid:0001&code=http%3A%2F%2Floinc.org|29463-7&date=2017-09-03T11:13:00-04:00");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends org.hl7.fhir.dstu3.model.Resource> T find(Bundle theBundle, Class<T> theType, int theIndex) {
|
||||
int count = 0;
|
||||
|
@ -200,36 +303,36 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
rpt = myDiagnosticReportDao.read(rptId);
|
||||
assertThat(rpt.getResult(), empty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleUpdatesWithNoChangesDoesNotResultInAnUpdateForTransaction() {
|
||||
Bundle bundle;
|
||||
|
||||
|
||||
// First time
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Patient/A");
|
||||
Bundle resp = mySystemDao.transaction(mySrd, bundle);
|
||||
assertThat(resp.getEntry().get(0).getResponse().getLocation(), endsWith("Patient/A/_history/1"));
|
||||
|
||||
|
||||
// Second time should not result in an update
|
||||
p = new Patient();
|
||||
p.setActive(true);
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Patient/A");
|
||||
resp = mySystemDao.transaction(mySrd, bundle);
|
||||
|
@ -241,10 +344,10 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.setFullUrl("Patient/A")
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Patient/A");
|
||||
resp = mySystemDao.transaction(mySrd, bundle);
|
||||
|
@ -256,13 +359,13 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
myPatientDao.read(new IdType("Patient/A/_history/2"));
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
//good
|
||||
// good
|
||||
}
|
||||
try {
|
||||
myPatientDao.read(new IdType("Patient/A/_history/3"));
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
//good
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,60 +590,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceUuid() {
|
||||
Bundle request = new Bundle();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId(IdType.newRandomUuid());
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
o.getSubject().setReference(p.getId());
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||
assertThat(patientId, startsWith("Patient/"));
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
params.add("subject", new ReferenceParam(patientId));
|
||||
IBundleProvider found = myObservationDao.search(params);
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceResource() {
|
||||
Bundle request = new Bundle();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId(IdType.newRandomUuid());
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
o.getSubject().setResource(p);
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||
assertThat(patientId, startsWith("Patient/"));
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
params.add("subject", new ReferenceParam(patientId));
|
||||
IBundleProvider found = myObservationDao.search(params);
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateInlineMatchUrlWithOneMatch() {
|
||||
String methodName = "testTransactionCreateInlineMatchUrlWithOneMatch";
|
||||
|
@ -1335,7 +1384,8 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to process Transaction - Request would cause multiple resources to match URL: \"Encounter?identifier=urn:foo|12345\". Does transaction request contain duplicates?", e.getMessage());
|
||||
assertEquals("Unable to process Transaction - Request would cause multiple resources to match URL: \"Encounter?identifier=urn:foo|12345\". Does transaction request contain duplicates?",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1365,9 +1415,10 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unable to process Transaction - Request would cause multiple resources to match URL: \"Encounter?identifier=urn:foo|12345\". Does transaction request contain duplicates?", e.getMessage());
|
||||
assertEquals("Unable to process Transaction - Request would cause multiple resources to match URL: \"Encounter?identifier=urn:foo|12345\". Does transaction request contain duplicates?",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = InvalidRequestException.class)
|
||||
|
@ -2026,8 +2077,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
|
||||
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
|
@ -2040,7 +2090,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -2101,6 +2151,66 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
assertEquals(id0.toUnqualifiedVersionless().getValue(), app2.getParticipant().get(1).getActor().getReference());
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we are able to handle placeholder IDs in match URLs, e.g.
|
||||
*
|
||||
* "request": {
|
||||
* "method": "PUT",
|
||||
* "url": "Observation?subject=urn:uuid:8dba64a8-2aca-48fe-8b4e-8c7bf2ab695a&code=http%3A%2F%2Floinc.org|29463-7&date=2011-09-03T11:13:00-04:00"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPut() {
|
||||
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle output = mySystemDao.transaction(null, input);
|
||||
|
||||
assertEquals("201 Created", output.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle output2 = mySystemDao.transaction(null, input2);
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output2));
|
||||
|
||||
assertEquals("200 OK", output2.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("200 OK", output2.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("200 OK", output2.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we are able to handle placeholder IDs in match URLs, e.g.
|
||||
*
|
||||
* "request": {
|
||||
* "method": "PUT",
|
||||
* "url": "Observation?subject=urn:uuid:8dba64a8-2aca-48fe-8b4e-8c7bf2ab695a&code=http%3A%2F%2Floinc.org|29463-7&date=2011-09-03T11:13:00-04:00"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPost() {
|
||||
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle output = mySystemDao.transaction(null, input);
|
||||
|
||||
assertEquals("201 Created", output.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle output2 = mySystemDao.transaction(null, input2);
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output2));
|
||||
|
||||
assertEquals("200 OK", output2.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("200 OK", output2.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("200 OK", output2.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Per a message on the mailing list
|
||||
*/
|
||||
|
@ -2137,6 +2247,86 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
assertEquals("Joshua", patient.getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceResource() {
|
||||
Bundle request = new Bundle();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId(IdType.newRandomUuid());
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
o.getSubject().setResource(p);
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||
assertThat(patientId, startsWith("Patient/"));
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
params.add("subject", new ReferenceParam(patientId));
|
||||
IBundleProvider found = myObservationDao.search(params);
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceToCreateIfNoneExist() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
Medication med = new Medication();
|
||||
IdType medId = IdType.newRandomUuid();
|
||||
med.setId(medId);
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
MedicationRequest mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
ourLog.info("Request:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
ourLog.info("Response:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
|
||||
IdType medId1 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId1 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
/*
|
||||
* Again!
|
||||
*/
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
med = new Medication();
|
||||
medId = IdType.newRandomUuid();
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IdType medId2 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId2 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
assertTrue(medId1.isIdPartValidLong());
|
||||
assertTrue(medId2.isIdPartValidLong());
|
||||
assertTrue(medOrderId1.isIdPartValidLong());
|
||||
assertTrue(medOrderId2.isIdPartValidLong());
|
||||
|
||||
assertEquals(medId1, medId2);
|
||||
assertNotEquals(medOrderId1, medOrderId2);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// /**
|
||||
|
@ -2240,59 +2430,32 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
// }
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceToCreateIfNoneExist() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
public void testTransactionWithReferenceUuid() {
|
||||
Bundle request = new Bundle();
|
||||
|
||||
Medication med = new Medication();
|
||||
IdType medId = IdType.newRandomUuid();
|
||||
med.setId(medId);
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId(IdType.newRandomUuid());
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||
|
||||
MedicationRequest mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
o.getSubject().setReference(p.getId());
|
||||
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
ourLog.info("Request:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
ourLog.info("Response:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||
assertThat(patientId, startsWith("Patient/"));
|
||||
|
||||
IdType medId1 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId1 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
/*
|
||||
* Again!
|
||||
*/
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
med = new Medication();
|
||||
medId = IdType.newRandomUuid();
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IdType medId2 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId2 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
assertTrue(medId1.isIdPartValidLong());
|
||||
assertTrue(medId2.isIdPartValidLong());
|
||||
assertTrue(medOrderId1.isIdPartValidLong());
|
||||
assertTrue(medOrderId2.isIdPartValidLong());
|
||||
|
||||
assertEquals(medId1, medId2);
|
||||
assertNotEquals(medOrderId1, medOrderId2);
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
params.add("subject", new ReferenceParam(patientId));
|
||||
IBundleProvider found = myObservationDao.search(params);
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionWithRelativeOidIds() throws Exception {
|
||||
Bundle res = new Bundle();
|
||||
|
@ -2330,7 +2493,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
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
|
||||
|
|
|
@ -86,6 +86,8 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
|||
*/
|
||||
@DatatypeDef(name = "id", profileOf=StringType.class)
|
||||
public final class IdType extends UriType implements IPrimitiveType<String>, IIdType {
|
||||
public static final String URN_PREFIX = "urn:";
|
||||
|
||||
/**
|
||||
* This is the maximum length for the ID
|
||||
*/
|
||||
|
@ -486,8 +488,8 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
return defaultString(myUnqualifiedId).startsWith("#");
|
||||
}
|
||||
|
||||
private boolean isUrn() {
|
||||
return defaultString(myUnqualifiedId).startsWith("urn:");
|
||||
public boolean isUrn() {
|
||||
return defaultString(myUnqualifiedId).startsWith(URN_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -526,7 +528,7 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
myHaveComponentParts = true;
|
||||
} else if (theValue.startsWith("urn:")) {
|
||||
} else if (theValue.startsWith(URN_PREFIX)) {
|
||||
myBaseUrl = null;
|
||||
myUnqualifiedId = theValue;
|
||||
myUnqualifiedVersionId = null;
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
meant that any project using ookhttp would import both structures
|
||||
JARs. This has been removed.
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA server is now able to handle placeholder IDs (e.g. urn:uuid:00....000)
|
||||
being used in Bundle.entry.request.url as a part of the conditional URL
|
||||
within transactions.
|
||||
</action>
|
||||
</release
|
||||
<release version="2.6" date="TBD">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue