Fix NPE in MDM post-mdm-clear on UPDATE operations. (#3851)
* Fix bug, imlpementation, changelog * wip * wip * wip * Add test * wip * wip
This commit is contained in:
parent
a676506fc5
commit
57f6a705a5
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 3786
|
||||
title: "Previously, when executing an update on a resource that had to undergo MDM, a nullpointer could occur. This has been fixed."
|
|
@ -19,7 +19,6 @@
|
|||
*/
|
||||
package ca.uhn.fhir.jpa.mdm.svc;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||
import ca.uhn.fhir.jpa.mdm.svc.candidate.MatchedGoldenResourceCandidate;
|
||||
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
|
||||
|
@ -35,7 +34,6 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
|||
import ca.uhn.fhir.mdm.util.EIDHelper;
|
||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -82,6 +80,7 @@ public class MdmEidUpdateService {
|
|||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(
|
||||
theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext);
|
||||
|
||||
IAnyResource theOldGoldenResource = updateContext.getExistingGoldenResource();
|
||||
if (updateContext.isRemainsMatchedToSameGoldenResource()) {
|
||||
// Copy over any new external EIDs which don't already exist.
|
||||
if (!updateContext.isIncomingResourceHasAnEid() || updateContext.isHasEidsInCommon()) {
|
||||
|
@ -96,29 +95,35 @@ public class MdmEidUpdateService {
|
|||
handleNoEidsInCommon(
|
||||
theTargetResource, theMatchedGoldenResourceCandidate, theMdmTransactionContext, updateContext);
|
||||
}
|
||||
} else if (theOldGoldenResource == null) {
|
||||
// If we are in an update, and there is no existing golden resource, it is likely due to a clear operation,
|
||||
// and we need to start from scratch.
|
||||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(
|
||||
theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext);
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(
|
||||
updateContext.getMatchedGoldenResource(), theMdmTransactionContext.getResourceType());
|
||||
myMdmLinkSvc.updateLink(
|
||||
updateContext.getMatchedGoldenResource(),
|
||||
theTargetResource,
|
||||
theMatchedGoldenResourceCandidate.getMatchResult(),
|
||||
MdmLinkSourceEnum.AUTO,
|
||||
theMdmTransactionContext);
|
||||
} else {
|
||||
// This is a new linking scenario. we have to break the existing link and link to the new Golden Resource.
|
||||
// For now, we create duplicate.
|
||||
// updated patient has an EID that matches to a new candidate. Link them, and set the Golden Resources
|
||||
// possible duplicates
|
||||
IAnyResource theOldGoldenResource = updateContext.getExistingGoldenResource();
|
||||
if (theOldGoldenResource == null) {
|
||||
throw new InternalErrorException(
|
||||
Msg.code(2362)
|
||||
+ "Old golden resource was null while updating MDM links with new golden resource. It is likely that a $mdm-clear was performed without a $mdm-submit. Link will not be updated.");
|
||||
} else {
|
||||
linkToNewGoldenResourceAndFlagAsDuplicate(
|
||||
theTargetResource,
|
||||
theMatchedGoldenResourceCandidate.getMatchResult(),
|
||||
theOldGoldenResource,
|
||||
updateContext.getMatchedGoldenResource(),
|
||||
theMdmTransactionContext);
|
||||
linkToNewGoldenResourceAndFlagAsDuplicate(
|
||||
theTargetResource,
|
||||
theMatchedGoldenResourceCandidate.getMatchResult(),
|
||||
theOldGoldenResource,
|
||||
updateContext.getMatchedGoldenResource(),
|
||||
theMdmTransactionContext);
|
||||
|
||||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(
|
||||
theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext);
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(
|
||||
updateContext.getMatchedGoldenResource(), theMdmTransactionContext.getResourceType());
|
||||
}
|
||||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(
|
||||
theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext);
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(
|
||||
updateContext.getMatchedGoldenResource(), theMdmTransactionContext.getResourceType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,5 +288,9 @@ public class MdmEidUpdateService {
|
|||
public boolean isRemainsMatchedToSameGoldenResource() {
|
||||
return myRemainsMatchedToSameGoldenResource;
|
||||
}
|
||||
|
||||
public boolean hasExistingGoldenResource() {
|
||||
return myExistingGoldenResource != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -626,6 +626,14 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
|
|||
return retval;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected MdmTransactionContext buildUpdateResourceMdmTransactionContext() {
|
||||
MdmTransactionContext retval = new MdmTransactionContext();
|
||||
retval.setResourceType("Patient");
|
||||
retval.setRestOperation(MdmTransactionContext.OperationType.UPDATE_RESOURCE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
protected MdmLink createGoldenPatientAndLinkToSourcePatient(Long thePatientPid, MdmMatchResultEnum theMdmMatchResultEnum) {
|
||||
Patient patient = createPatient();
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package ca.uhn.fhir.jpa.mdm.interceptor;
|
||||
|
||||
import ca.uhn.fhir.batch2.api.StepExecutionDetails;
|
||||
import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson;
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
|
||||
|
@ -7,7 +10,11 @@ import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
|
|||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.batch2.clear.MdmClearJobParameters;
|
||||
import ca.uhn.fhir.mdm.batch2.clear.MdmClearStep;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
@ -20,7 +27,11 @@ import org.springframework.data.domain.Example;
|
|||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package ca.uhn.fhir.jpa.mdm.svc;
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
import ca.uhn.fhir.jpa.mdm.config.BaseTestMdmConfig;
|
||||
|
@ -80,7 +82,6 @@ public class MdmMatchLinkSvcTest {
|
|||
|
||||
private static final Logger ourLog = getLogger(MdmMatchLinkSvcTest.class);
|
||||
|
||||
|
||||
@Nested
|
||||
public class NoBlockLinkTest extends BaseMdmR4Test {
|
||||
@Autowired
|
||||
|
@ -231,9 +232,26 @@ public class MdmMatchLinkSvcTest {
|
|||
assertLinksMatchVector(null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenPOSSIBLE_MATCHOccursOnGoldenResourceThatHasBeenManuallyNOMATCHedThatItIsBlocked() {
|
||||
Patient originalJane = createPatientAndUpdateLinks(buildJanePatient());
|
||||
@Test
|
||||
public void updateMdmLinksForMdmSource_singleCandidateDuringUpdate_DoesNotNullPointer() {
|
||||
|
||||
//Given: A patient exists with a matched golden resource.
|
||||
Patient jane = createPatientAndUpdateLinks(buildJanePatient());
|
||||
Patient goldenJane = getGoldenResourceFromTargetResource(jane);
|
||||
|
||||
//When: A patient who has no existing MDM links comes in as an update
|
||||
Patient secondaryJane = createPatient(buildJanePatient(), false, false);
|
||||
secondaryJane.setActive(true);
|
||||
IAnyResource resource = (IAnyResource) myPatientDao.update(secondaryJane).getResource();
|
||||
|
||||
//Then: The secondary jane should link to the first jane.
|
||||
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(resource, buildUpdateResourceMdmTransactionContext());
|
||||
assertThat(secondaryJane, is(sameGoldenResourceAs(jane)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenPOSSIBLE_MATCHOccursOnGoldenResourceThatHasBeenManuallyNOMATCHedThatItIsBlocked() {
|
||||
Patient originalJane = createPatientAndUpdateLinks(buildJanePatient());
|
||||
|
||||
IBundleProvider search = myPatientDao.search(buildGoldenRecordSearchParameterMap());
|
||||
IAnyResource janeGoldenResource = (IAnyResource) search.getResources(0, 1).get(0);
|
||||
|
|
Loading…
Reference in New Issue