Accept placeholder IDs in the JPA server even if they have no resource type in references to them (as is actually correct)
This commit is contained in:
parent
4ab8871a41
commit
e536486638
|
@ -210,9 +210,10 @@ public class FhirSystemDaoDstu1 extends BaseFhirSystemDao<List<IResource>> {
|
|||
ourLog.info("Transaction resource ID[{}] is being updated", newId);
|
||||
} else {
|
||||
if (!nextId.getIdPart().startsWith("#")) {
|
||||
nextId = new IdDt(resourceName + '/' + nextId.getIdPart());
|
||||
nextId = new IdDt(resourceName, nextId.getIdPart());
|
||||
ourLog.info("Transaction resource ID[{}] has been assigned new ID[{}]", nextId, newId);
|
||||
idConversions.put(nextId, newId);
|
||||
idConversions.put(new IdDt(nextId.getIdPart()), newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
|||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryTransactionResponse;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
@ -165,257 +166,97 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
}
|
||||
|
||||
switch (verb) {
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDao(res.getClass());
|
||||
res.setId((String)null);
|
||||
DaoMethodOutcome outcome;
|
||||
Entry newEntry = response.addEntry();
|
||||
outcome = resourceDao.create(res, nextEntry.getTransaction().getIfNoneExist(), false);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
break;
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDao(res.getClass());
|
||||
res.setId((String) null);
|
||||
DaoMethodOutcome outcome;
|
||||
Entry newEntry = response.addEntry();
|
||||
outcome = resourceDao.create(res, nextEntry.getTransaction().getIfNoneExist(), false);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
break;
|
||||
}
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
Entry newEntry = response.addEntry();
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
if (parts.getResourceId() != null) {
|
||||
parts.getDao().delete(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
} else {
|
||||
parts.getDao().deleteByUrl(parts.getResourceType() + '?' + parts.getParams());
|
||||
}
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
Entry newEntry = response.addEntry();
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
if (parts.getResourceId() != null) {
|
||||
parts.getDao().delete(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
|
||||
newEntry.getTransactionResponse().setStatus(Integer.toString(Constants.STATUS_HTTP_204_NO_CONTENT));
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDao(res.getClass());
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
Entry newEntry = response.addEntry();
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
outcome = resourceDao.update(res, null, false);
|
||||
} else {
|
||||
res.setId((String) null);
|
||||
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false);
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
break;
|
||||
}
|
||||
case GET: {
|
||||
// SEARCH/READ/VREAD
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = parts.getDao();
|
||||
|
||||
if (parts.getResourceId() != null && parts.getParams() == null) {
|
||||
IResource found;
|
||||
if (parts.getVersionId() != null) {
|
||||
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId()));
|
||||
} else {
|
||||
parts.getDao().deleteByUrl(parts.getResourceType() + '?' + parts.getParams());
|
||||
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
}
|
||||
EntryTransactionResponse resp = response.addEntry().setResource(found).getTransactionResponse();
|
||||
resp.setLocation(found.getId().toUnqualified().getValue());
|
||||
resp.setEtag(found.getId().getVersionIdPart());
|
||||
} else if (parts.getParams() != null) {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(parts.getDao().getResourceType());
|
||||
SearchParameterMap params = translateMatchUrl(url, def);
|
||||
IBundleProvider bundle = parts.getDao().search(params);
|
||||
|
||||
Bundle searchBundle = new Bundle();
|
||||
searchBundle.setTotal(bundle.size());
|
||||
|
||||
int configuredMax = 100; // this should probably be configurable or something
|
||||
if (bundle.size() > configuredMax) {
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions");
|
||||
}
|
||||
List<IBaseResource> resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax));
|
||||
for (IBaseResource next : resourcesToAdd) {
|
||||
searchBundle.addEntry().setResource((IResource) next);
|
||||
}
|
||||
|
||||
newEntry.getTransactionResponse().setStatus(Integer.toString(Constants.STATUS_HTTP_204_NO_CONTENT));
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDao(res.getClass());
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
Entry newEntry = response.addEntry();
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
// if (res.getId().hasIdPart() && isBlank(parts.getResourceId())) {
|
||||
// parts.setResourceId(res.getId().getIdPart());
|
||||
// }
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
outcome = resourceDao.update(res, null, false);
|
||||
} else {
|
||||
res.setId((String)null);
|
||||
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false);
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
break;
|
||||
}
|
||||
case GET: {
|
||||
// SEARCH/READ/VREAD
|
||||
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
|
||||
UrlParts parts = parseUrl(verb.getCode(), url);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = parts.getDao();
|
||||
|
||||
if (parts.getResourceId() != null && parts.getParams() == null) {
|
||||
IResource found;
|
||||
if (parts.getVersionId() != null) {
|
||||
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId()));
|
||||
} else {
|
||||
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
}
|
||||
EntryTransactionResponse resp = response.addEntry().setResource(found).getTransactionResponse();
|
||||
resp.setLocation(found.getId().toUnqualified().getValue());
|
||||
resp.setEtag(found.getId().getVersionIdPart());
|
||||
} else if (parts.getParams() != null) {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(parts.getDao().getResourceType());
|
||||
SearchParameterMap params = translateMatchUrl(url, def);
|
||||
IBundleProvider bundle = parts.getDao().search(params);
|
||||
|
||||
Bundle searchBundle = new Bundle();
|
||||
searchBundle.setTotal(bundle.size());
|
||||
|
||||
int configuredMax = 100; // this should probably be configurable or something
|
||||
if (bundle.size() > configuredMax) {
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions");
|
||||
}
|
||||
List<IBaseResource> resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax));
|
||||
for (IBaseResource next : resourcesToAdd) {
|
||||
searchBundle.addEntry().setResource((IResource) next);
|
||||
}
|
||||
|
||||
response.addEntry().setResource(searchBundle);
|
||||
}
|
||||
response.addEntry().setResource(searchBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FhirTerser terser = getContext().newTerser();
|
||||
|
||||
// int creations = 0;
|
||||
// int updates = 0;
|
||||
//
|
||||
// Map<IdDt, IdDt> idConversions = new HashMap<IdDt, IdDt>();
|
||||
//
|
||||
// List<ResourceTable> persistedResources = new ArrayList<ResourceTable>();
|
||||
//
|
||||
// List<IResource> retVal = new ArrayList<IResource>();
|
||||
// OperationOutcome oo = new OperationOutcome();
|
||||
// retVal.add(oo);
|
||||
//
|
||||
// for (int resourceIdx = 0; resourceIdx < theResources.size(); resourceIdx++) {
|
||||
// IResource nextResource = theResources.get(resourceIdx);
|
||||
//
|
||||
// IdDt nextId = nextResource.getId();
|
||||
// if (nextId == null) {
|
||||
// nextId = new IdDt();
|
||||
// }
|
||||
//
|
||||
// String resourceName = toResourceName(nextResource);
|
||||
// BundleEntryTransactionOperationEnum nextResouceOperationIn =
|
||||
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(nextResource);
|
||||
// if (nextResouceOperationIn == null && hasValue(ResourceMetadataKeyEnum.DELETED_AT.get(nextResource))) {
|
||||
// nextResouceOperationIn = BundleEntryTransactionOperationEnum.DELETE;
|
||||
// }
|
||||
//
|
||||
// String matchUrl = ResourceMetadataKeyEnum.LINK_SEARCH.get(nextResource);
|
||||
// Set<Long> candidateMatches = null;
|
||||
// if (StringUtils.isNotBlank(matchUrl)) {
|
||||
// candidateMatches = processMatchUrl(matchUrl, nextResource.getClass());
|
||||
// }
|
||||
//
|
||||
// ResourceTable entity;
|
||||
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
|
||||
// entity = null;
|
||||
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE || nextResouceOperationIn ==
|
||||
// BundleEntryTransactionOperationEnum.DELETE) {
|
||||
// if (candidateMatches == null || candidateMatches.size() == 0) {
|
||||
// if (nextId == null || StringUtils.isBlank(nextId.getIdPart())) {
|
||||
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
|
||||
// "transactionOperationFailedNoId", nextResouceOperationIn.name()));
|
||||
// }
|
||||
// entity = tryToLoadEntity(nextId);
|
||||
// if (entity == null) {
|
||||
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE) {
|
||||
// ourLog.debug("Attempting to UPDATE resource with unknown ID '{}', will CREATE instead", nextId);
|
||||
// } else if (candidateMatches == null) {
|
||||
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
|
||||
// "transactionOperationFailedUnknownId", nextResouceOperationIn.name(), nextId));
|
||||
// } else {
|
||||
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
|
||||
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource,
|
||||
// BundleEntryTransactionOperationEnum.NOOP);
|
||||
// persistedResources.add(null);
|
||||
// retVal.add(nextResource);
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
// } else if (candidateMatches.size() == 1) {
|
||||
// entity = loadFirstEntityFromCandidateMatches(candidateMatches);
|
||||
// } else {
|
||||
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
|
||||
// "transactionOperationWithMultipleMatchFailure", nextResouceOperationIn.name(), matchUrl,
|
||||
// candidateMatches.size()));
|
||||
// }
|
||||
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.NOOP) {
|
||||
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
|
||||
// "incomingNoopInTransaction"));
|
||||
// } else if (nextId.isEmpty()) {
|
||||
// entity = null;
|
||||
// } else {
|
||||
// entity = tryToLoadEntity(nextId);
|
||||
// }
|
||||
//
|
||||
// BundleEntryTransactionOperationEnum nextResouceOperationOut;
|
||||
// if (entity == null) {
|
||||
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.CREATE;
|
||||
// entity = toEntity(nextResource);
|
||||
// if (nextId.isEmpty() == false && nextId.getIdPart().startsWith("cid:")) {
|
||||
// ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
|
||||
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
|
||||
// if (nextId.isEmpty() == false) {
|
||||
// ourLog.debug("Resource in transaction has ID[{}] but is marked for CREATE, will ignore ID",
|
||||
// nextId.getIdPart());
|
||||
// }
|
||||
// if (candidateMatches != null) {
|
||||
// if (candidateMatches.size() == 1) {
|
||||
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
|
||||
// BaseHasResource existingEntity = loadFirstEntityFromCandidateMatches(candidateMatches);
|
||||
// IResource existing = (IResource) toResource(existingEntity);
|
||||
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(existing, BundleEntryTransactionOperationEnum.NOOP);
|
||||
// persistedResources.add(null);
|
||||
// retVal.add(existing);
|
||||
// continue;
|
||||
// }
|
||||
// if (candidateMatches.size() > 1) {
|
||||
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
|
||||
// "transactionOperationWithMultipleMatchFailure", BundleEntryTransactionOperationEnum.CREATE.name(), matchUrl,
|
||||
// candidateMatches.size()));
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// createForcedIdIfNeeded(entity, nextId);
|
||||
// }
|
||||
// myEntityManager.persist(entity);
|
||||
// if (entity.getForcedId() != null) {
|
||||
// myEntityManager.persist(entity.getForcedId());
|
||||
// }
|
||||
// creations++;
|
||||
// ourLog.info("Resource Type[{}] with ID[{}] does not exist, creating it", resourceName, nextId);
|
||||
// } else {
|
||||
// nextResouceOperationOut = nextResouceOperationIn;
|
||||
// if (nextResouceOperationOut == null) {
|
||||
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.UPDATE;
|
||||
// }
|
||||
// updates++;
|
||||
// ourLog.info("Resource Type[{}] with ID[{}] exists, updating it", resourceName, nextId);
|
||||
// }
|
||||
//
|
||||
// persistedResources.add(entity);
|
||||
// retVal.add(nextResource);
|
||||
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, nextResouceOperationOut);
|
||||
// }
|
||||
//
|
||||
// ourLog.info("Flushing transaction to database");
|
||||
// myEntityManager.flush();
|
||||
//
|
||||
// for (int i = 0; i < persistedResources.size(); i++) {
|
||||
// ResourceTable entity = persistedResources.get(i);
|
||||
//
|
||||
// String resourceName = toResourceName(theResources.get(i));
|
||||
// IdDt nextId = theResources.get(i).getId();
|
||||
//
|
||||
// IdDt newId;
|
||||
//
|
||||
// if (entity == null) {
|
||||
// newId = retVal.get(i + 1).getId().toUnqualifiedVersionless();
|
||||
// } else {
|
||||
// newId = entity.getIdDt().toUnqualifiedVersionless();
|
||||
// }
|
||||
//
|
||||
// if (nextId == null || nextId.isEmpty()) {
|
||||
// ourLog.info("Transaction resource (with no preexisting ID) has been assigned new ID[{}]", nextId, newId);
|
||||
// } else {
|
||||
// if (nextId.toUnqualifiedVersionless().equals(newId)) {
|
||||
// ourLog.info("Transaction resource ID[{}] is being updated", newId);
|
||||
// } else {
|
||||
// if (!nextId.getIdPart().startsWith("#")) {
|
||||
// nextId = new IdDt(resourceName + '/' + nextId.getIdPart());
|
||||
// ourLog.info("Transaction resource ID[{}] has been assigned new ID[{}]", nextId, newId);
|
||||
// idConversions.put(nextId, newId);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
|
||||
IResource nextResource = nextOutcome.getResource();
|
||||
if (nextResource == null) {
|
||||
|
@ -438,49 +279,41 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false);
|
||||
}
|
||||
//
|
||||
// ourLog.info("Re-flushing updated resource references and extracting search criteria");
|
||||
//
|
||||
// for (int i = 0; i < theResources.size(); i++) {
|
||||
// IResource resource = theResources.get(i);
|
||||
// ResourceTable table = persistedResources.get(i);
|
||||
// if (table == null) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(resource);
|
||||
// Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
// if (deletedInstantOrNull == null && ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(resource) ==
|
||||
// BundleEntryTransactionOperationEnum.DELETE) {
|
||||
// deletedTimestampOrNull = new Date();
|
||||
// ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
|
||||
// }
|
||||
//
|
||||
// updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull);
|
||||
// }
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
ourLog.info("Transaction completed in {}ms", new Object[]{delay});
|
||||
ourLog.info("Transaction completed in {}ms", new Object[] { delay });
|
||||
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Transaction completed in " + delay + "ms");
|
||||
|
||||
for (IdDt next : allIds) {
|
||||
IdDt replacement = idSubstitutions.get(next);
|
||||
if (replacement == null) {
|
||||
continue;
|
||||
}
|
||||
if (replacement.equals(next)) {
|
||||
continue;
|
||||
}
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Placeholder resource ID \"" + next + "\" was replaced with permanent ID \"" + replacement + "\"");
|
||||
}
|
||||
|
||||
notifyWriteCompleted();
|
||||
|
||||
response.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaDt metaGetOperation() {
|
||||
|
||||
|
||||
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();
|
||||
|
||||
MetaDt retVal = super.toMetaDt(tagDefinitions);
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) {
|
||||
String url = nextEntry.getTransaction().getUrl();
|
||||
if (isBlank(url)) {
|
||||
|
@ -493,7 +326,12 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
IdDt newId = outcome.getId().toUnqualifiedVersionless();
|
||||
IdDt resourceId = nextResourceId.toUnqualifiedVersionless();
|
||||
if (newId.equals(resourceId) == false) {
|
||||
/*
|
||||
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified
|
||||
* kind too just to be lenient.
|
||||
*/
|
||||
idSubstitutions.put(resourceId, newId);
|
||||
idSubstitutions.put(resourceId.withResourceType(null), newId);
|
||||
}
|
||||
idToPersistedOutcome.put(newId, outcome);
|
||||
if (outcome.getCreated().booleanValue()) {
|
||||
|
|
|
@ -303,7 +303,8 @@ public class FhirSystemDaoDstu1Test {
|
|||
|
||||
|
||||
/**
|
||||
* Issue #55
|
||||
* Issue #55. Note that this is the incorrect way to
|
||||
* do this but we'll leave it since people may depend on it.
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithCidIds() throws Exception {
|
||||
|
@ -337,6 +338,41 @@ public class FhirSystemDaoDstu1Test {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the correct way to do this, not {@link #testTransactionWithCidIds()}
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithCidIdsUnqualified() throws Exception {
|
||||
List<IResource> res = new ArrayList<IResource>();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId("cid:patient1");
|
||||
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified01");
|
||||
res.add(p1);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.setId("cid:observation1");
|
||||
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified02");
|
||||
o1.setSubject(new ResourceReferenceDt("cid:patient1"));
|
||||
res.add(o1);
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.setId("cid:observation2");
|
||||
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified03");
|
||||
o2.setSubject(new ResourceReferenceDt("cid:patient1"));
|
||||
res.add(o2);
|
||||
|
||||
ourSystemDao.transaction(res);
|
||||
|
||||
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
|
||||
|
||||
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithDelete() throws Exception {
|
||||
|
||||
|
|
|
@ -5,12 +5,7 @@ import static org.hamcrest.Matchers.emptyString;
|
|||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
@ -31,6 +26,7 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
|
@ -57,7 +53,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
private static IFhirResourceDao<Patient> ourPatientDao;
|
||||
private static IFhirSystemDao<Bundle> ourSystemDao;
|
||||
private static IFhirResourceDao<Observation> ourObservationDao;
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateMatchUrlWithOneMatch() {
|
||||
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
|
||||
|
@ -144,24 +140,22 @@ public class FhirSystemDaoDstu2Test {
|
|||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/transaction_link_patient_eve.xml");
|
||||
String bundleStr = IOUtils.toString(bundleRes);
|
||||
Bundle bundle = ourFhirContext.newXmlParser().parseResource(Bundle.class, bundleStr);
|
||||
|
||||
|
||||
Bundle resp = ourSystemDao.transaction(bundle);
|
||||
|
||||
|
||||
ourLog.info(ourFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) resp.getEntry().get(0).getResource();
|
||||
assertThat(oo.getIssue().get(0).getDetailsElement().getValue(), containsString("Transaction completed"));
|
||||
|
||||
|
||||
assertThat(resp.getEntry().get(1).getTransactionResponse().getLocation(), startsWith("Patient/a555-44-4444/_history/"));
|
||||
assertThat(resp.getEntry().get(2).getTransactionResponse().getLocation(), startsWith("Patient/temp6789/_history/"));
|
||||
assertThat(resp.getEntry().get(3).getTransactionResponse().getLocation(), startsWith("Organization/GHH/_history/"));
|
||||
|
||||
|
||||
Patient p = ourPatientDao.read(new IdDt("Patient/a555-44-4444/_history/1"));
|
||||
assertEquals("Patient/temp6789", p.getLink().get(0).getOther().getReference().getValue());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionReadAndSearch() {
|
||||
String methodName = "testTransactionReadAndSearch";
|
||||
|
@ -561,7 +555,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
|
||||
Observation o = new Observation();
|
||||
o.getCode().setText("Some Observation");
|
||||
o.getSubject().setReference("Patient/"+methodName);
|
||||
o.getSubject().setReference("Patient/" + methodName);
|
||||
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
|
||||
|
||||
Bundle resp = ourSystemDao.transaction(request);
|
||||
|
@ -623,6 +617,99 @@ public class FhirSystemDaoDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithRelativeOidIds() throws Exception {
|
||||
Bundle res = new Bundle();
|
||||
res.setType(BundleTypeEnum.TRANSACTION);
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId("urn:oid:0.1.2.3");
|
||||
p1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds01");
|
||||
res.addEntry().setResource(p1).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Patient");
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.setId("cid:observation1");
|
||||
o1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds02");
|
||||
o1.setSubject(new ResourceReferenceDt("urn:oid:0.1.2.3"));
|
||||
res.addEntry().setResource(o1).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Observation");
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.setId("cid:observation2");
|
||||
o2.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds03");
|
||||
o2.setSubject(new ResourceReferenceDt("urn:oid:0.1.2.3"));
|
||||
res.addEntry().setResource(o2).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Observation");
|
||||
|
||||
Bundle resp = ourSystemDao.transaction(res);
|
||||
|
||||
ourLog.info(ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
assertEquals(BundleTypeEnum.TRANSACTION_RESPONSE, resp.getTypeElement().getValueAsEnum());
|
||||
assertEquals(4, resp.getEntry().size());
|
||||
|
||||
assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass());
|
||||
|
||||
OperationOutcome outcome = (OperationOutcome) resp.getEntry().get(0).getResource();
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"Patient/urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
|
||||
assertTrue(resp.getEntry().get(1).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(2).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(3).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(3).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
|
||||
o1 = ourObservationDao.read(new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()));
|
||||
o2 = ourObservationDao.read(new IdDt(resp.getEntry().get(3).getTransactionResponse().getLocation()));
|
||||
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not the correct way to do it, but we'll allow it to be lenient
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithRelativeOidIdsQualified() throws Exception {
|
||||
Bundle res = new Bundle();
|
||||
res.setType(BundleTypeEnum.TRANSACTION);
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId("urn:oid:0.1.2.3");
|
||||
p1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds01");
|
||||
res.addEntry().setResource(p1).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Patient");
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.setId("cid:observation1");
|
||||
o1.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds02");
|
||||
o1.setSubject(new ResourceReferenceDt("Patient/urn:oid:0.1.2.3"));
|
||||
res.addEntry().setResource(o1).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Observation");
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.setId("cid:observation2");
|
||||
o2.addIdentifier().setSystem("system").setValue("testTransactionWithRelativeOidIds03");
|
||||
o2.setSubject(new ResourceReferenceDt("Patient/urn:oid:0.1.2.3"));
|
||||
res.addEntry().setResource(o2).getTransaction().setMethod(HTTPVerbEnum.POST).setUrl("Observation");
|
||||
|
||||
Bundle resp = ourSystemDao.transaction(res);
|
||||
|
||||
ourLog.info(ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
assertEquals(BundleTypeEnum.TRANSACTION_RESPONSE, resp.getTypeElement().getValueAsEnum());
|
||||
assertEquals(4, resp.getEntry().size());
|
||||
|
||||
assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass());
|
||||
|
||||
OperationOutcome outcome = (OperationOutcome) resp.getEntry().get(0).getResource();
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"Patient/urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
|
||||
assertTrue(resp.getEntry().get(1).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(2).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(3).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(3).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
|
||||
o1 = ourObservationDao.read(new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()));
|
||||
o2 = ourObservationDao.read(new IdDt(resp.getEntry().get(3).getTransactionResponse().getLocation()));
|
||||
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// /**
|
||||
|
@ -744,7 +831,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
@Test
|
||||
public void testSystemMetaOperation() {
|
||||
deleteEverything();
|
||||
|
||||
|
||||
MetaDt meta = ourSystemDao.metaGetOperation();
|
||||
List<CodingDt> published = meta.getTag();
|
||||
assertEquals(0, published.size());
|
||||
|
@ -841,7 +928,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
for (IBaseResource iResource : allRes) {
|
||||
if (ResourceMetadataKeyEnum.DELETED_AT.get((IResource) iResource) == null) {
|
||||
ourLog.info("Deleting: {}", iResource.getIdElement());
|
||||
|
||||
|
||||
Bundle b = new Bundle();
|
||||
b.setType(BundleTypeEnum.TRANSACTION);
|
||||
String url = iResource.getIdElement().toVersionless().getValue();
|
||||
|
@ -849,7 +936,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
systemDao.transaction(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
systemDao.deleteAllTagsOnServer();
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,17 @@
|
|||
Some HTML entities were not correctly converted during parsing. Thanks to
|
||||
Nick Kitto for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
In the JPA Server:
|
||||
Transactions creating resources with temporary/placeholder resource IDs
|
||||
and other resources with references to those placeholder IDs previously
|
||||
did not work if the reference did not contain the resource type
|
||||
(e.g. Patient/urn:oid:0.1.2.3 instead of urn:oid:0.1.2.3). The
|
||||
latter is actually the correct way of specifying a reference to a
|
||||
placeholder, but the former was the only way that worked. Both forms
|
||||
now work, in order to be lenient. Thanks to Bill De Beaubien for
|
||||
reporting!
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.0" date="2015-May-8">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue