Addressed more code review comments
This commit is contained in:
parent
efb429b319
commit
4c7b597983
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||||
import ca.uhn.fhir.mdm.util.EIDHelper;
|
import ca.uhn.fhir.mdm.util.EIDHelper;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
@ -84,7 +84,7 @@ public class MdmStorageInterceptor implements IMdmStorageInterceptor {
|
||||||
forbidIfHasMultipleEids(theUpdatedResource);
|
forbidIfHasMultipleEids(theUpdatedResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myGoldenResourceHelper.isDeactivated(theUpdatedResource)) {
|
if (MdmResourceUtil.isGoldenRecordRedirected(theUpdatedResource)) {
|
||||||
ourLog.debug("Deleting MDM links to deactivated Golden resource {}", theUpdatedResource.getIdElement().toUnqualifiedVersionless());
|
ourLog.debug("Deleting MDM links to deactivated Golden resource {}", theUpdatedResource.getIdElement().toUnqualifiedVersionless());
|
||||||
int deleted = myMdmLinkDeleteSvc.deleteNonRedirectWithAnyReferenceTo(theUpdatedResource);
|
int deleted = myMdmLinkDeleteSvc.deleteNonRedirectWithAnyReferenceTo(theUpdatedResource);
|
||||||
if (deleted > 0) {
|
if (deleted > 0) {
|
||||||
|
@ -131,7 +131,7 @@ public class MdmStorageInterceptor implements IMdmStorageInterceptor {
|
||||||
* Will throw a forbidden error if a request attempts to add/remove the MDM tag on a Resource.
|
* Will throw a forbidden error if a request attempts to add/remove the MDM tag on a Resource.
|
||||||
*/
|
*/
|
||||||
private void forbidModifyingMdmTag(IBaseResource theNewResource, IBaseResource theOldResource) {
|
private void forbidModifyingMdmTag(IBaseResource theNewResource, IBaseResource theOldResource) {
|
||||||
if (MdmUtil.isMdmManaged(theNewResource) != MdmUtil.isMdmManaged(theOldResource)) {
|
if (MdmResourceUtil.isMdmManaged(theNewResource) != MdmResourceUtil.isMdmManaged(theOldResource)) {
|
||||||
throwBlockMdmManagedTagChange();
|
throwBlockMdmManagedTagChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,10 +153,10 @@ public class MdmStorageInterceptor implements IMdmStorageInterceptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forbidIfMdmManagedTagIsPresent(IBaseResource theResource) {
|
private void forbidIfMdmManagedTagIsPresent(IBaseResource theResource) {
|
||||||
if (MdmUtil.isMdmManaged(theResource)) {
|
if (MdmResourceUtil.isMdmManaged(theResource)) {
|
||||||
throwModificationBlockedByMdm();
|
throwModificationBlockedByMdm();
|
||||||
}
|
}
|
||||||
if (MdmUtil.hasGoldenRecordSystemTag(theResource)) {
|
if (MdmResourceUtil.hasGoldenRecordSystemTag(theResource)) {
|
||||||
throwModificationBlockedByMdm();
|
throwModificationBlockedByMdm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -77,7 +78,7 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
|
||||||
myMdmResourceDaoSvc.removeGoldenResourceTag(theFromGoldenResource, resourceType);
|
myMdmResourceDaoSvc.removeGoldenResourceTag(theFromGoldenResource, resourceType);
|
||||||
|
|
||||||
//Add the REDIRECT tag to that same deprecated resource.
|
//Add the REDIRECT tag to that same deprecated resource.
|
||||||
myGoldenResourceHelper.deactivateResource(theFromGoldenResource);
|
MdmResourceUtil.setGoldenResourceRedirected(theFromGoldenResource);
|
||||||
|
|
||||||
//Save the deprecated resource.
|
//Save the deprecated resource.
|
||||||
myMdmResourceDaoSvc.upsertGoldenResource(theFromGoldenResource, resourceType);
|
myMdmResourceDaoSvc.upsertGoldenResource(theFromGoldenResource, resourceType);
|
||||||
|
|
|
@ -28,7 +28,7 @@ import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.log.Logs;
|
import ca.uhn.fhir.mdm.log.Logs;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||||
|
@ -117,11 +117,11 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
||||||
throw new InvalidRequestException(myMessageHelper.getMessageForArgumentTypeMismatchInUpdate(goldenRecordType, theSourceType));
|
throw new InvalidRequestException(myMessageHelper.getMessageForArgumentTypeMismatchInUpdate(goldenRecordType, theSourceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MdmUtil.isMdmManaged(theGoldenRecord)) {
|
if (!MdmResourceUtil.isMdmManaged(theGoldenRecord)) {
|
||||||
throw new InvalidRequestException(myMessageHelper.getMessageForUnmanagedResource());
|
throw new InvalidRequestException(myMessageHelper.getMessageForUnmanagedResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MdmUtil.isMdmAllowed(theSourceResource)) {
|
if (!MdmResourceUtil.isMdmAllowed(theSourceResource)) {
|
||||||
throw new InvalidRequestException(myMessageHelper.getMessageForUnsupportedSourceResource());
|
throw new InvalidRequestException(myMessageHelper.getMessageForUnsupportedSourceResource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
||||||
throw new InvalidRequestException("First argument to " + ProviderConstants.MDM_UPDATE_LINK + " must be the same resource type as the second argument. Was " + goldenResourceType + "/" + targetType);
|
throw new InvalidRequestException("First argument to " + ProviderConstants.MDM_UPDATE_LINK + " must be the same resource type as the second argument. Was " + goldenResourceType + "/" + targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MdmUtil.isMdmManaged(theGoldenResource) || !MdmUtil.isMdmManaged(theTarget)) {
|
if (!MdmResourceUtil.isMdmManaged(theGoldenResource) || !MdmResourceUtil.isMdmManaged(theTarget)) {
|
||||||
throw new InvalidRequestException("Only MDM Managed Golden Resources may be updated via this operation. The resource provided is not tagged as managed by HAPI-MDM");
|
throw new InvalidRequestException("Only MDM Managed Golden Resources may be updated via this operation. The resource provided is not tagged as managed by HAPI-MDM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
|
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
|
||||||
import ca.uhn.fhir.mdm.log.Logs;
|
import ca.uhn.fhir.mdm.log.Logs;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateList;
|
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateList;
|
||||||
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
|
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
|
||||||
|
@ -67,7 +67,7 @@ public class MdmMatchLinkSvc {
|
||||||
* @return an {@link TransactionLogMessages} which contains all informational messages related to MDM processing of this resource.
|
* @return an {@link TransactionLogMessages} which contains all informational messages related to MDM processing of this resource.
|
||||||
*/
|
*/
|
||||||
public MdmTransactionContext updateMdmLinksForMdmSource(IAnyResource theResource, MdmTransactionContext theMdmTransactionContext) {
|
public MdmTransactionContext updateMdmLinksForMdmSource(IAnyResource theResource, MdmTransactionContext theMdmTransactionContext) {
|
||||||
if (MdmUtil.isMdmAllowed(theResource)) {
|
if (MdmResourceUtil.isMdmAllowed(theResource)) {
|
||||||
return doMdmUpdate(theResource, theMdmTransactionContext);
|
return doMdmUpdate(theResource, theMdmTransactionContext);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.log.Logs;
|
import ca.uhn.fhir.mdm.log.Logs;
|
||||||
import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson;
|
import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -56,7 +56,7 @@ public class MdmResourceFilteringSvc {
|
||||||
* @return whether or not MDM processing should proceed
|
* @return whether or not MDM processing should proceed
|
||||||
*/
|
*/
|
||||||
public boolean shouldBeProcessed(IAnyResource theResource) {
|
public boolean shouldBeProcessed(IAnyResource theResource) {
|
||||||
if (MdmUtil.isMdmManaged(theResource)) {
|
if (MdmResourceUtil.isMdmManaged(theResource)) {
|
||||||
ourLog.debug("MDM Message handler is dropping [{}] as it is MDM-managed.", theResource);
|
ourLog.debug("MDM Message handler is dropping [{}] as it is MDM-managed.", theResource);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc;
|
import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc;
|
||||||
import ca.uhn.fhir.mdm.util.EIDHelper;
|
import ca.uhn.fhir.mdm.util.EIDHelper;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||||
|
@ -160,11 +160,11 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
protected Patient createPatient(Patient thePatient, boolean theMdmManaged, boolean isRedirect) {
|
protected Patient createPatient(Patient thePatient, boolean theMdmManaged, boolean isRedirect) {
|
||||||
if (theMdmManaged) {
|
if (theMdmManaged) {
|
||||||
MdmUtil.setMdmManaged(thePatient);
|
MdmResourceUtil.setMdmManaged(thePatient);
|
||||||
if (isRedirect) {
|
if (isRedirect) {
|
||||||
MdmUtil.setGoldenResourceRedirected(thePatient);
|
MdmResourceUtil.setGoldenResourceRedirected(thePatient);
|
||||||
} else {
|
} else {
|
||||||
MdmUtil.setGoldenResource(thePatient);
|
MdmResourceUtil.setGoldenResource(thePatient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.mdm.matcher;
|
package ca.uhn.fhir.jpa.mdm.matcher;
|
||||||
|
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
|
@ -36,7 +36,7 @@ public abstract class BaseGoldenResourceMatcher extends TypeSafeMatcher<IAnyReso
|
||||||
protected Long getMatchedResourcePidFromResource(IAnyResource theResource) {
|
protected Long getMatchedResourcePidFromResource(IAnyResource theResource) {
|
||||||
Long retval;
|
Long retval;
|
||||||
|
|
||||||
boolean isGoldenRecord = MdmUtil.isMdmManaged(theResource);
|
boolean isGoldenRecord = MdmResourceUtil.isMdmManaged(theResource);
|
||||||
if (isGoldenRecord) {
|
if (isGoldenRecord) {
|
||||||
return myIdHelperService.getPidOrNull(theResource);
|
return myIdHelperService.getPidOrNull(theResource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ca.uhn.fhir.jpa.mdm.provider;
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
@ -43,7 +43,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
||||||
Patient mergedSourcePatient = (Patient) myMdmProviderR4.mergeGoldenResources(myFromGoldenPatientId,
|
Patient mergedSourcePatient = (Patient) myMdmProviderR4.mergeGoldenResources(myFromGoldenPatientId,
|
||||||
myToGoldenPatientId, myRequestDetails);
|
myToGoldenPatientId, myRequestDetails);
|
||||||
|
|
||||||
assertTrue(MdmUtil.isGoldenRecord(myFromGoldenPatient));
|
assertTrue(MdmResourceUtil.isGoldenRecord(myFromGoldenPatient));
|
||||||
assertEquals(myToGoldenPatient.getIdElement(), mergedSourcePatient.getIdElement());
|
assertEquals(myToGoldenPatient.getIdElement(), mergedSourcePatient.getIdElement());
|
||||||
assertThat(mergedSourcePatient, is(sameGoldenResourceAs(myToGoldenPatient)));
|
assertThat(mergedSourcePatient, is(sameGoldenResourceAs(myToGoldenPatient)));
|
||||||
assertEquals(1, getAllRedirectedGoldenPatients().size());
|
assertEquals(1, getAllRedirectedGoldenPatients().size());
|
||||||
|
@ -51,7 +51,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
||||||
|
|
||||||
Patient fromSourcePatient = myPatientDao.read(myFromGoldenPatient.getIdElement().toUnqualifiedVersionless());
|
Patient fromSourcePatient = myPatientDao.read(myFromGoldenPatient.getIdElement().toUnqualifiedVersionless());
|
||||||
assertThat(fromSourcePatient.getActive(), is(false));
|
assertThat(fromSourcePatient.getActive(), is(false));
|
||||||
assertTrue(MdmUtil.isGoldenRecordRedirected(fromSourcePatient));
|
assertTrue(MdmResourceUtil.isGoldenRecordRedirected(fromSourcePatient));
|
||||||
|
|
||||||
//TODO GGG eventually this will need to check a redirect... this is a hack which doesnt work
|
//TODO GGG eventually this will need to check a redirect... this is a hack which doesnt work
|
||||||
// Optional<Identifier> redirect = fromSourcePatient.getIdentifier().stream().filter(theIdentifier -> theIdentifier.getSystem().equals("REDIRECT")).findFirst();
|
// Optional<Identifier> redirect = fromSourcePatient.getIdentifier().stream().filter(theIdentifier -> theIdentifier.getSystem().equals("REDIRECT")).findFirst();
|
||||||
|
|
|
@ -10,7 +10,7 @@ import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||||
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||||
import ca.uhn.fhir.mdm.util.EIDHelper;
|
import ca.uhn.fhir.mdm.util.EIDHelper;
|
||||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
@ -446,7 +446,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
|
||||||
Patient janeGoldenResourcePatient = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(janePatient);
|
Patient janeGoldenResourcePatient = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(janePatient);
|
||||||
|
|
||||||
// golden record now contains HAPI-generated EID and HAPI tag
|
// golden record now contains HAPI-generated EID and HAPI tag
|
||||||
assertTrue(MdmUtil.isMdmManaged(janeGoldenResourcePatient));
|
assertTrue(MdmResourceUtil.isMdmManaged(janeGoldenResourcePatient));
|
||||||
assertFalse(myEidHelper.getHapiEid(janeGoldenResourcePatient).isEmpty());
|
assertFalse(myEidHelper.getHapiEid(janeGoldenResourcePatient).isEmpty());
|
||||||
|
|
||||||
// original checks - verifies that EIDs are assigned
|
// original checks - verifies that EIDs are assigned
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.mdm.svc;
|
package ca.uhn.fhir.jpa.mdm.svc;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -26,7 +26,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
||||||
|
|
||||||
|
|
||||||
Patient badSourcePatient = addExternalEID(createRedirectedGoldenPatient(new Patient()), TEST_EID);
|
Patient badSourcePatient = addExternalEID(createRedirectedGoldenPatient(new Patient()), TEST_EID);
|
||||||
MdmUtil.setGoldenResourceRedirected(badSourcePatient);
|
MdmResourceUtil.setGoldenResourceRedirected(badSourcePatient);
|
||||||
myPatientDao.update(badSourcePatient);
|
myPatientDao.update(badSourcePatient);
|
||||||
|
|
||||||
Optional<IAnyResource> foundGoldenResource = myResourceDaoSvc.searchGoldenResourceByEID(TEST_EID, "Patient");
|
Optional<IAnyResource> foundGoldenResource = myResourceDaoSvc.searchGoldenResourceByEID(TEST_EID, "Patient");
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
package ca.uhn.fhir.mdm.model;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Master Data Management
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.hl7.fhir.r4.model.Person;
|
|
||||||
|
|
||||||
public enum CanonicalIdentityAssuranceLevel {
|
|
||||||
LEVEL1("level1"),
|
|
||||||
LEVEL2("level2"),
|
|
||||||
LEVEL3("level3"),
|
|
||||||
LEVEL4("level4");
|
|
||||||
|
|
||||||
private String myCanonicalLevel;
|
|
||||||
private CanonicalIdentityAssuranceLevel(String theCanonicalLevel) {
|
|
||||||
myCanonicalLevel = theCanonicalLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Person.IdentityAssuranceLevel toR4() {
|
|
||||||
return Person.IdentityAssuranceLevel.fromCode(myCanonicalLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.hl7.fhir.dstu3.model.Person.IdentityAssuranceLevel toDstu3() {
|
|
||||||
return org.hl7.fhir.dstu3.model.Person.IdentityAssuranceLevel.fromCode(myCanonicalLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -22,7 +22,7 @@ package ca.uhn.fhir.mdm.provider;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.util.MdmUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
@ -94,7 +94,7 @@ public class MdmControllerHelper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MdmUtil.isMdmManaged(theResource)) {
|
if (!MdmResourceUtil.isMdmManaged(theResource)) {
|
||||||
throw new InvalidRequestException(myMessageHelper.getMessageForUnmanagedResource());
|
throw new InvalidRequestException(myMessageHelper.getMessageForUnmanagedResource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
package ca.uhn.fhir.mdm.util;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Master Data Management
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
|
||||||
import ca.uhn.fhir.mdm.model.CanonicalIdentityAssuranceLevel;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class to determine assurance level based on Link Source and Match Result.
|
|
||||||
* This is strictly for use in populating Golden Resource links.
|
|
||||||
*/
|
|
||||||
public final class AssuranceLevelUtil {
|
|
||||||
|
|
||||||
private AssuranceLevelUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CanonicalIdentityAssuranceLevel getAssuranceLevel(MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theSource) {
|
|
||||||
switch (theSource) {
|
|
||||||
case MANUAL:
|
|
||||||
return getAssuranceFromManualResult(theMatchResult);
|
|
||||||
case AUTO:
|
|
||||||
return getAssuranceFromAutoResult(theMatchResult);
|
|
||||||
}
|
|
||||||
throw new InvalidRequestException("Couldn't figure out an assurance level for result: " + theMatchResult + " and source " + theSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CanonicalIdentityAssuranceLevel getAssuranceFromAutoResult(MdmMatchResultEnum theMatchResult) {
|
|
||||||
switch (theMatchResult) {
|
|
||||||
case MATCH:
|
|
||||||
return CanonicalIdentityAssuranceLevel.LEVEL2;
|
|
||||||
case POSSIBLE_MATCH:
|
|
||||||
return CanonicalIdentityAssuranceLevel.LEVEL1;
|
|
||||||
case POSSIBLE_DUPLICATE:
|
|
||||||
case NO_MATCH:
|
|
||||||
default:
|
|
||||||
throw new InvalidRequestException("An AUTO MDM Link may not have a match result of " + theMatchResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CanonicalIdentityAssuranceLevel getAssuranceFromManualResult(MdmMatchResultEnum theMatchResult) {
|
|
||||||
switch (theMatchResult) {
|
|
||||||
case MATCH:
|
|
||||||
case REDIRECT:
|
|
||||||
return CanonicalIdentityAssuranceLevel.LEVEL3;
|
|
||||||
case NO_MATCH:
|
|
||||||
case POSSIBLE_DUPLICATE:
|
|
||||||
case POSSIBLE_MATCH:
|
|
||||||
default:
|
|
||||||
throw new InvalidRequestException("A MANUAL MDM Link may not have a match result of " + theMatchResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,7 +35,6 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.BooleanType;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -54,7 +53,7 @@ public class GoldenResourceHelper {
|
||||||
|
|
||||||
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
|
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
|
||||||
|
|
||||||
private static final String FIELD_NAME_IDENTIFIER = "identifier";
|
static final String FIELD_NAME_IDENTIFIER = "identifier";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMdmSettings myMdmSettings;
|
private IMdmSettings myMdmSettings;
|
||||||
|
@ -90,8 +89,8 @@ public class GoldenResourceHelper {
|
||||||
|
|
||||||
addHapiEidIfNoExternalEidIsPresent(newGoldenResource, goldenResourceIdentifier, theIncomingResource);
|
addHapiEidIfNoExternalEidIsPresent(newGoldenResource, goldenResourceIdentifier, theIncomingResource);
|
||||||
|
|
||||||
MdmUtil.setMdmManaged(newGoldenResource);
|
MdmResourceUtil.setMdmManaged(newGoldenResource);
|
||||||
MdmUtil.setGoldenResource(newGoldenResource);
|
MdmResourceUtil.setGoldenResource(newGoldenResource);
|
||||||
|
|
||||||
return (T) newGoldenResource;
|
return (T) newGoldenResource;
|
||||||
}
|
}
|
||||||
|
@ -109,69 +108,10 @@ public class GoldenResourceHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
CanonicalEID hapiEid = myEIDHelper.createHapiEid();
|
CanonicalEID hapiEid = myEIDHelper.createHapiEid();
|
||||||
theGoldenResourceIdentifier.getMutator().addValue(theNewGoldenResource, toId(hapiEid));
|
theGoldenResourceIdentifier.getMutator().addValue(theNewGoldenResource, IdentifierUtil.toId(myFhirContext, hapiEid));
|
||||||
|
|
||||||
// set identifier on the source resource
|
// set identifier on the source resource
|
||||||
cloneEidIntoResource(theSourceResource, hapiEid);
|
TerserUtil.cloneEidIntoResource(myFhirContext, theSourceResource, hapiEid);
|
||||||
}
|
|
||||||
|
|
||||||
private void cloneEidIntoResource(IBaseResource theResourceToCloneInto, CanonicalEID theEid) {
|
|
||||||
// get a ref to the actual ID Field
|
|
||||||
RuntimeResourceDefinition resourceDefinition = myFhirContext.getResourceDefinition(theResourceToCloneInto);
|
|
||||||
// hapi has 2 metamodels: for children and types
|
|
||||||
BaseRuntimeChildDefinition resourceIdentifier = resourceDefinition.getChildByName(FIELD_NAME_IDENTIFIER);
|
|
||||||
cloneEidIntoResource(resourceIdentifier, toId(theEid), theResourceToCloneInto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an Child Definition of `identifier`, a R4/DSTU3 EID Identifier, and a new resource, clone the EID into that resources' identifier list.
|
|
||||||
*/
|
|
||||||
private void cloneEidIntoResource(BaseRuntimeChildDefinition theIdentifierDefinition, IBase theEid, IBase theResourceToCloneEidInto) {
|
|
||||||
// FHIR choice types - fields within fhir where we have a choice of ids
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> childIdentifier = (BaseRuntimeElementCompositeDefinition<?>) theIdentifierDefinition.getChildByName(FIELD_NAME_IDENTIFIER);
|
|
||||||
IBase resourceNewIdentifier = childIdentifier.newInstance();
|
|
||||||
|
|
||||||
FhirTerser terser = myFhirContext.newTerser();
|
|
||||||
terser.cloneInto(theEid, resourceNewIdentifier, true);
|
|
||||||
theIdentifierDefinition.getMutator().addValue(theResourceToCloneEidInto, resourceNewIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clones specified composite field (collection). Composite field values must confirm to the collections
|
|
||||||
* contract.
|
|
||||||
*
|
|
||||||
* @param theFrom Resource to clone the specified filed from
|
|
||||||
* @param theTo Resource to clone the specified filed to
|
|
||||||
* @param field Field name to be copied
|
|
||||||
*/
|
|
||||||
private void cloneCompositeField(IBaseResource theFrom, IBaseResource theTo, String field) {
|
|
||||||
FhirTerser terser = myFhirContext.newTerser();
|
|
||||||
|
|
||||||
RuntimeResourceDefinition definition = myFhirContext.getResourceDefinition(theFrom);
|
|
||||||
BaseRuntimeChildDefinition childDefinition = definition.getChildByName(field);
|
|
||||||
|
|
||||||
IFhirPath fhirPath = myFhirContext.newFhirPath();
|
|
||||||
List<IBase> theFromFieldValues = childDefinition.getAccessor().getValues(theFrom);
|
|
||||||
List<IBase> theToFieldValues = childDefinition.getAccessor().getValues(theTo);
|
|
||||||
|
|
||||||
for (IBase theFromFieldValue : theFromFieldValues) {
|
|
||||||
if (contains(theFromFieldValue, theToFieldValues)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> compositeDefinition = (BaseRuntimeElementCompositeDefinition<?>) childDefinition.getChildByName(field);
|
|
||||||
IBase newFieldValue = compositeDefinition.newInstance();
|
|
||||||
terser.cloneInto(theFromFieldValue, newFieldValue, true);
|
|
||||||
|
|
||||||
theToFieldValues.add(newFieldValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean contains(IBase theItem, List<IBase> theItems) {
|
|
||||||
PrimitiveTypeComparingPredicate predicate = new PrimitiveTypeComparingPredicate();
|
|
||||||
return theItems.stream().filter(i -> {
|
|
||||||
return predicate.test(i, theItem);
|
|
||||||
}).findFirst().isPresent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cloneAllExternalEidsIntoNewGoldenResource(BaseRuntimeChildDefinition theGoldenResourceIdentifier,
|
private void cloneAllExternalEidsIntoNewGoldenResource(BaseRuntimeChildDefinition theGoldenResourceIdentifier,
|
||||||
|
@ -186,7 +126,7 @@ public class GoldenResourceHelper {
|
||||||
String mdmSystem = myMdmSettings.getMdmRules().getEnterpriseEIDSystem();
|
String mdmSystem = myMdmSettings.getMdmRules().getEnterpriseEIDSystem();
|
||||||
String baseSystem = system.get().getValueAsString();
|
String baseSystem = system.get().getValueAsString();
|
||||||
if (Objects.equals(baseSystem, mdmSystem)) {
|
if (Objects.equals(baseSystem, mdmSystem)) {
|
||||||
cloneEidIntoResource(theGoldenResourceIdentifier, base, theNewGoldenResource);
|
TerserUtil.cloneEidIntoResource(myFhirContext, theGoldenResourceIdentifier, base, theNewGoldenResource);
|
||||||
ourLog.debug("System {} differs from system in the MDM rules {}", baseSystem, mdmSystem);
|
ourLog.debug("System {} differs from system in the MDM rules {}", baseSystem, mdmSystem);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -292,45 +232,14 @@ public class GoldenResourceHelper {
|
||||||
if (goldenResourceExternalEids.contains(incomingExternalEid)) {
|
if (goldenResourceExternalEids.contains(incomingExternalEid)) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
cloneEidIntoResource(theGoldenResource, incomingExternalEid);
|
TerserUtil.cloneEidIntoResource(myFhirContext, theGoldenResource, incomingExternalEid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends IBase> T toId(CanonicalEID eid) {
|
|
||||||
switch (myFhirContext.getVersion().getVersion()) {
|
|
||||||
case R4:
|
|
||||||
return (T) eid.toR4();
|
|
||||||
case DSTU3:
|
|
||||||
return (T) eid.toDSTU3();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private <T extends IBase> T toBooleanType(boolean theFlag) {
|
|
||||||
switch (myFhirContext.getVersion().getVersion()) {
|
|
||||||
case R4:
|
|
||||||
return (T) new BooleanType(theFlag);
|
|
||||||
case DSTU3:
|
|
||||||
return (T) new org.hl7.fhir.dstu3.model.BooleanType(theFlag);
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends IBase> boolean fromBooleanType(T theFlag) {
|
|
||||||
switch (myFhirContext.getVersion().getVersion()) {
|
|
||||||
case R4:
|
|
||||||
return ((BooleanType) theFlag).booleanValue();
|
|
||||||
case DSTU3:
|
|
||||||
return ((org.hl7.fhir.dstu3.model.BooleanType) theFlag).booleanValue();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mergeFields(IBaseResource theFromGoldenResource, IBaseResource theToGoldenResource) {
|
public void mergeFields(IBaseResource theFromGoldenResource, IBaseResource theToGoldenResource) {
|
||||||
// TODO NG - Revisit when merge rules are defined
|
// TODO NG - Revisit when merge rules are defined
|
||||||
cloneCompositeField(theFromGoldenResource, theToGoldenResource, FIELD_NAME_IDENTIFIER);
|
TerserUtil.cloneCompositeField(myFhirContext, theFromGoldenResource, theToGoldenResource, FIELD_NAME_IDENTIFIER);
|
||||||
|
|
||||||
// switch (myFhirContext.getVersion().getVersion()) {
|
// switch (myFhirContext.getVersion().getVersion()) {
|
||||||
// case R4:
|
// case R4:
|
||||||
|
@ -366,12 +275,4 @@ public class GoldenResourceHelper {
|
||||||
updateGoldenResourceExternalEidFromSourceResource(theGoldenResource, theSourceResource, theMdmTransactionContext);
|
updateGoldenResourceExternalEidFromSourceResource(theGoldenResource, theSourceResource, theMdmTransactionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deactivateResource(IAnyResource theResource) {
|
|
||||||
MdmUtil.setGoldenResourceRedirected(theResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDeactivated(IBaseResource theGoldenResource) {
|
|
||||||
return MdmUtil.isGoldenRecordRedirected(theGoldenResource);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,15 @@ package ca.uhn.fhir.mdm.util;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
|
||||||
public class IdentifierUtil {
|
public final class IdentifierUtil {
|
||||||
|
|
||||||
|
private IdentifierUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
public static CanonicalIdentifier identifierDtFromIdentifier(IBase theIdentifier) {
|
public static CanonicalIdentifier identifierDtFromIdentifier(IBase theIdentifier) {
|
||||||
CanonicalIdentifier retval = new CanonicalIdentifier();
|
CanonicalIdentifier retval = new CanonicalIdentifier();
|
||||||
|
@ -43,4 +48,22 @@ public class IdentifierUtil {
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves appropriate FHIR Identifier model instance based on the context version
|
||||||
|
*
|
||||||
|
* @param theFhirContext FHIR context to use for determining the identifier version
|
||||||
|
* @param eid EID to get equivalent FHIR Identifier from
|
||||||
|
* @param <T> Generic Identifier base interface
|
||||||
|
* @return Returns appropriate R4 or DSTU3 Identifier instance
|
||||||
|
*/
|
||||||
|
public static <T extends IBase> T toId(FhirContext theFhirContext, CanonicalEID eid) {
|
||||||
|
switch (theFhirContext.getVersion().getVersion()) {
|
||||||
|
case R4:
|
||||||
|
return (T) eid.toR4();
|
||||||
|
case DSTU3:
|
||||||
|
return (T) eid.toDSTU3();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unsupported FHIR version " + theFhirContext.getVersion().getVersion());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public final class MdmUtil {
|
public final class MdmResourceUtil {
|
||||||
|
|
||||||
private MdmUtil() {
|
private MdmResourceUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -29,7 +29,11 @@ import org.hl7.fhir.r4.model.PrimitiveType;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class NameUtil {
|
public final class NameUtil {
|
||||||
|
|
||||||
|
private NameUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
public static List<String> extractGivenNames(FhirContext theFhirContext, IBase theBase) {
|
public static List<String> extractGivenNames(FhirContext theFhirContext, IBase theBase) {
|
||||||
switch(theFhirContext.getVersion().getVersion()) {
|
switch(theFhirContext.getVersion().getVersion()) {
|
||||||
case R4:
|
case R4:
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
|
||||||
public class PrimitiveTypeComparingPredicate implements BiPredicate {
|
public class PrimitiveTypeEqualsPredicate implements BiPredicate {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean test(Object theBase1, Object theBase2) {
|
public boolean test(Object theBase1, Object theBase2) {
|
|
@ -0,0 +1,86 @@
|
||||||
|
package ca.uhn.fhir.mdm.util;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||||
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.mdm.util.GoldenResourceHelper.FIELD_NAME_IDENTIFIER;
|
||||||
|
|
||||||
|
final class TerserUtil {
|
||||||
|
|
||||||
|
private TerserUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the specified canonical EID into the identifier field on the resource
|
||||||
|
*
|
||||||
|
* @param theFhirContext Context to pull resource definitions from
|
||||||
|
* @param theResourceToCloneInto Resource to set the EID on
|
||||||
|
* @param theEid EID to be set
|
||||||
|
*/
|
||||||
|
public static void cloneEidIntoResource(FhirContext theFhirContext, IBaseResource theResourceToCloneInto, CanonicalEID theEid) {
|
||||||
|
// get a ref to the actual ID Field
|
||||||
|
RuntimeResourceDefinition resourceDefinition = theFhirContext.getResourceDefinition(theResourceToCloneInto);
|
||||||
|
// hapi has 2 metamodels: for children and types
|
||||||
|
BaseRuntimeChildDefinition resourceIdentifier = resourceDefinition.getChildByName(FIELD_NAME_IDENTIFIER);
|
||||||
|
cloneEidIntoResource(theFhirContext, resourceIdentifier, IdentifierUtil.toId(theFhirContext, theEid), theResourceToCloneInto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an Child Definition of `identifier`, a R4/DSTU3 EID Identifier, and a new resource, clone the EID into that resources' identifier list.
|
||||||
|
*/
|
||||||
|
public static void cloneEidIntoResource(FhirContext theFhirContext, BaseRuntimeChildDefinition theIdentifierDefinition, IBase theEid, IBase theResourceToCloneEidInto) {
|
||||||
|
// FHIR choice types - fields within fhir where we have a choice of ids
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> childIdentifier = (BaseRuntimeElementCompositeDefinition<?>) theIdentifierDefinition.getChildByName(FIELD_NAME_IDENTIFIER);
|
||||||
|
IBase resourceNewIdentifier = childIdentifier.newInstance();
|
||||||
|
|
||||||
|
FhirTerser terser = theFhirContext.newTerser();
|
||||||
|
terser.cloneInto(theEid, resourceNewIdentifier, true);
|
||||||
|
theIdentifierDefinition.getMutator().addValue(theResourceToCloneEidInto, resourceNewIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones specified composite field (collection). Composite field values must confirm to the collections
|
||||||
|
* contract.
|
||||||
|
*
|
||||||
|
* @param theFrom Resource to clone the specified filed from
|
||||||
|
* @param theTo Resource to clone the specified filed to
|
||||||
|
* @param field Field name to be copied
|
||||||
|
*/
|
||||||
|
public static void cloneCompositeField(FhirContext theFhirContext, IBaseResource theFrom, IBaseResource theTo, String field) {
|
||||||
|
FhirTerser terser = theFhirContext.newTerser();
|
||||||
|
|
||||||
|
RuntimeResourceDefinition definition = theFhirContext.getResourceDefinition(theFrom);
|
||||||
|
BaseRuntimeChildDefinition childDefinition = definition.getChildByName(field);
|
||||||
|
|
||||||
|
List<IBase> theFromFieldValues = childDefinition.getAccessor().getValues(theFrom);
|
||||||
|
List<IBase> theToFieldValues = childDefinition.getAccessor().getValues(theTo);
|
||||||
|
|
||||||
|
for (IBase theFromFieldValue : theFromFieldValues) {
|
||||||
|
if (contains(theFromFieldValue, theToFieldValues)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> compositeDefinition = (BaseRuntimeElementCompositeDefinition<?>) childDefinition.getChildByName(field);
|
||||||
|
IBase newFieldValue = compositeDefinition.newInstance();
|
||||||
|
terser.cloneInto(theFromFieldValue, newFieldValue, true);
|
||||||
|
|
||||||
|
theToFieldValues.add(newFieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contains(IBase theItem, List<IBase> theItems) {
|
||||||
|
PrimitiveTypeEqualsPredicate predicate = new PrimitiveTypeEqualsPredicate();
|
||||||
|
return theItems.stream().anyMatch(i -> {
|
||||||
|
return predicate.test(i, theItem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,65 +0,0 @@
|
||||||
package ca.uhn.fhir.mdm.util;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmLinkSourceEnum.AUTO;
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmLinkSourceEnum.MANUAL;
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.MATCH;
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.NO_MATCH;
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.POSSIBLE_DUPLICATE;
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.POSSIBLE_MATCH;
|
|
||||||
import static ca.uhn.fhir.mdm.model.CanonicalIdentityAssuranceLevel.LEVEL1;
|
|
||||||
import static ca.uhn.fhir.mdm.model.CanonicalIdentityAssuranceLevel.LEVEL2;
|
|
||||||
import static ca.uhn.fhir.mdm.model.CanonicalIdentityAssuranceLevel.LEVEL3;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.core.Is.is;
|
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
public class AssuranceLevelUtilTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidPersonLinkLevels() {
|
|
||||||
assertThat(AssuranceLevelUtil.getAssuranceLevel(POSSIBLE_MATCH, AUTO), is(equalTo(LEVEL1)));
|
|
||||||
assertThat(AssuranceLevelUtil.getAssuranceLevel(MATCH, AUTO), is(equalTo(LEVEL2)));
|
|
||||||
assertThat(AssuranceLevelUtil.getAssuranceLevel(MATCH, MANUAL), is(equalTo(LEVEL3)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInvalidPersonLinkLevels() {
|
|
||||||
try {
|
|
||||||
AssuranceLevelUtil.getAssuranceLevel(NO_MATCH, AUTO);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("An AUTO MDM Link may not have a match result of NO_MATCH", e.getMessage());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
AssuranceLevelUtil.getAssuranceLevel(POSSIBLE_DUPLICATE, AUTO);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("An AUTO MDM Link may not have a match result of POSSIBLE_DUPLICATE", e.getMessage());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
AssuranceLevelUtil.getAssuranceLevel(NO_MATCH, MANUAL);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("A MANUAL MDM Link may not have a match result of NO_MATCH", e.getMessage());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
AssuranceLevelUtil.getAssuranceLevel(POSSIBLE_MATCH, MANUAL);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("A MANUAL MDM Link may not have a match result of POSSIBLE_MATCH", e.getMessage());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
AssuranceLevelUtil.getAssuranceLevel(POSSIBLE_DUPLICATE, MANUAL);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("A MANUAL MDM Link may not have a match result of POSSIBLE_DUPLICATE", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,8 +7,8 @@ import org.hl7.fhir.r4.model.Address;
|
||||||
import org.hl7.fhir.r4.model.BooleanType;
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
import org.hl7.fhir.r4.model.DateType;
|
import org.hl7.fhir.r4.model.DateType;
|
||||||
import org.hl7.fhir.r4.model.Enumerations;
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
import org.hl7.fhir.r4.model.Identifier;
|
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.Person;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -18,7 +18,7 @@ import java.util.Collections;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
class PrimitiveTypeComparingPredicateTest {
|
class PrimitiveTypeEqualsPredicateTest {
|
||||||
|
|
||||||
private static FhirContext myFhirContext;
|
private static FhirContext myFhirContext;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class PrimitiveTypeComparingPredicateTest {
|
||||||
|
|
||||||
private IBase myNegativeTest;
|
private IBase myNegativeTest;
|
||||||
|
|
||||||
private PrimitiveTypeComparingPredicate cut = new PrimitiveTypeComparingPredicate();
|
private PrimitiveTypeEqualsPredicate cut = new PrimitiveTypeEqualsPredicate();
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void initContext() {
|
public static void initContext() {
|
||||||
|
@ -47,10 +47,10 @@ class PrimitiveTypeComparingPredicateTest {
|
||||||
myPositiveTest2 = newPatient();
|
myPositiveTest2 = newPatient();
|
||||||
myPositiveTest3 = newPatient();
|
myPositiveTest3 = newPatient();
|
||||||
|
|
||||||
Patient patient = newPatient();
|
Patient inactivePatientForNegativeTest = newPatient();
|
||||||
patient.setActive(false);
|
inactivePatientForNegativeTest.setActive(false);
|
||||||
patient.setMultipleBirth(new BooleanType(false));
|
inactivePatientForNegativeTest.setMultipleBirth(new BooleanType(false));
|
||||||
myNegativeTest = patient;
|
myNegativeTest = inactivePatientForNegativeTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Patient newPatient() {
|
private Patient newPatient() {
|
||||||
|
@ -76,29 +76,22 @@ class PrimitiveTypeComparingPredicateTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNegativeMatchOnDifferentTypes() {
|
public void testNegativeMatchOnDifferentTypes() {
|
||||||
Patient patient = newPatient();
|
Person person = new Person();
|
||||||
Identifier identifier = patient.addIdentifier();
|
person.addName().addGiven("John");
|
||||||
identifier.setValue("TEST_VALUE");
|
assertFalse(cut.test(myNegativeTest, person));
|
||||||
assertFalse(cut.test(myNegativeTest, identifier));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSymmetry() {
|
public void testNulls() {
|
||||||
|
assertTrue(cut.test(null, null));
|
||||||
|
assertFalse(cut.test(myPositiveTest1, null));
|
||||||
|
assertFalse(cut.test(null, myPositiveTest1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPositiveMatchOnTheSameType() {
|
||||||
assertTrue(cut.test(myPositiveTest1, myPositiveTest2));
|
assertTrue(cut.test(myPositiveTest1, myPositiveTest2));
|
||||||
assertTrue(cut.test(myPositiveTest2, myPositiveTest1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReflexivity() {
|
|
||||||
assertTrue(cut.test(myPositiveTest1, myPositiveTest1));
|
assertTrue(cut.test(myPositiveTest1, myPositiveTest1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransitivity() {
|
|
||||||
assertTrue(cut.test(myPositiveTest1, myPositiveTest2));
|
|
||||||
assertTrue(cut.test(myPositiveTest2, myPositiveTest3));
|
|
||||||
assertTrue(cut.test(myPositiveTest1, myPositiveTest3));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue