adding pointcuts for mdm operations (#5116)
* adding pointcuts for mdm operations * adding changelog * cleanup * cleaning up * formatting * review fixes * formatting * more cleanup * cleanup * moving changelog * fixing a bug * cleanup * formatting * version bump * fixing broken merge * fixing the version --------- Co-authored-by: leif stawnyczy <leifstawnyczy@leifs-MacBook-Pro.local>
This commit is contained in:
parent
fd5c2c2862
commit
a48c602f71
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -2250,7 +2250,7 @@ public enum Pointcut implements IPointcut {
|
|||
* <ul>
|
||||
* <li>ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage - This parameter should not be modified as processing is complete when this hook is invoked.</li>
|
||||
* <li>ca.uhn.fhir.rest.server.TransactionLogMessages - This parameter is for informational messages provided by the MDM module during MDM processing.</li>
|
||||
* <li>ca.uhn.fhir.mdm.api.MdmLinkChangeEvent - Contains information about the change event, including target and golden resource IDs and the operation type.</li>
|
||||
* <li>ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent - Contains information about the change event, including target and golden resource IDs and the operation type.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -2261,7 +2261,192 @@ public enum Pointcut implements IPointcut {
|
|||
void.class,
|
||||
"ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage",
|
||||
"ca.uhn.fhir.rest.server.TransactionLogMessages",
|
||||
"ca.uhn.fhir.mdm.api.MdmLinkEvent"),
|
||||
"ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Create Link</b>
|
||||
* This hook is invoked after an MDM link is created,
|
||||
* and changes have been persisted to the database.
|
||||
* <p>
|
||||
* Hook may accept the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed, including details such as the
|
||||
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||
* pulled out of the servlet request.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.api.MdmLinkChangeEvent - Contains information about the link event, including target and golden resource IDs and the operation type.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Hooks should return <code>void</code>.
|
||||
* </p>
|
||||
*/
|
||||
MDM_POST_CREATE_LINK(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Update Link</b>
|
||||
* This hook is invoked after an MDM link is updated,
|
||||
* and changes have been persisted to the database.
|
||||
* <p>
|
||||
* Hook may accept the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed, including details such as the
|
||||
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||
* pulled out of the servlet request.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.api.MdmLinkChangeEvent - Contains information about the link event, including target and golden resource IDs and the operation type.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Hooks should return <code>void</code>.
|
||||
* </p>
|
||||
*/
|
||||
MDM_POST_UPDATE_LINK(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Merge Golden Resources</b>
|
||||
* This hook is invoked after 2 golden resources have been
|
||||
* merged together and results persisted.
|
||||
* <p>
|
||||
* Hook may accept the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed, including details such as the
|
||||
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||
* pulled out of the servlet request.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent - Contains information about the from and to resources.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Hooks should return <code>void</code>.
|
||||
* </p>
|
||||
*/
|
||||
MDM_POST_MERGE_GOLDEN_RESOURCES(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Link History Hook:</b>
|
||||
* This hook is invoked after link histories are queried,
|
||||
* but before the results are returned to the caller.
|
||||
* <p>
|
||||
* Hook may accept the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.model.mdmevents.MdmHistoryEvent - An MDM History Event containing
|
||||
* information about the requested golden resource ids and/or source ids input, and
|
||||
* the returned link histories.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
MDM_POST_LINK_HISTORY(
|
||||
void.class,
|
||||
"ca.uhn.fhir.rest.api.server.RequestDetails",
|
||||
"ca.uhn.fhir.mdm.model.mdmevents.MdmHistoryEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Not Duplicate/Unduplicate Hook:</b>
|
||||
* This hook is invoked after 2 golden resources with an existing link
|
||||
* of "POSSIBLE_DUPLICATE" get unlinked/unduplicated.
|
||||
* <p>
|
||||
* This hook accepts the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent - the resulting final link
|
||||
* between the 2 golden resources; now a NO_MATCH link.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
MDM_POST_NOT_DUPLICATE(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Clear Hook:</b>
|
||||
* This hook is invoked when an mdm clear operation is requested.
|
||||
* <p>
|
||||
* This hook accepts the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.model.mdmevents.MdmClearEvent - the event containing information on the clear command,
|
||||
* including the type filter (if any) and the batch size (if any).
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
MDM_CLEAR(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmClearEvent"),
|
||||
|
||||
/**
|
||||
* <b>MDM Submit Hook:</b>
|
||||
* This hook is invoked whenever when mdm submit operation is requested.
|
||||
* MDM submits can be invoked in multiple ways.
|
||||
* Some of which accept asynchronous calling, and some of which do not.
|
||||
* <p>
|
||||
* If the MDM Submit operation is asynchronous
|
||||
* (typically because the Prefer: respond-async header has been provided)
|
||||
* this hook will be invoked after the job is submitted, but before it has
|
||||
* necessarily been executed.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the MDM Submit operation is synchronous,
|
||||
* this hook will be invoked immediately after the submit operation
|
||||
* has been executed, but before the call is returned to the caller.
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* On Patient Type. Can be synchronous or asynchronous.
|
||||
* </li>
|
||||
* <li>
|
||||
* On Practitioner Type. Can be synchronous or asynchronous.
|
||||
* </li>
|
||||
* <li>
|
||||
* On specific patient instances. Is always synchronous.
|
||||
* </li>
|
||||
* <li>
|
||||
* On specific practitioner instances. Is always synchronous.
|
||||
* </li>
|
||||
* <li>
|
||||
* On the server (ie, not on any resource) with or without a resource filter.
|
||||
* Can be synchronous or asynchronous.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* In all cases, this hook will take the following parameters:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* ca.uhn.fhir.rest.api.server.RequestDetails - An object containing details about the request that is about to be processed.
|
||||
* </li>
|
||||
* <li>
|
||||
* ca.uhn.fhir.mdm.model.mdmevents.MdmSubmitEvent - An event with the Mdm Submit information
|
||||
* (urls specifying paths that will be searched for MDM submit, as well as
|
||||
* if this was an asynchronous request or not).
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
MDM_SUBMIT(
|
||||
void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmSubmitEvent"),
|
||||
|
||||
/**
|
||||
* <b>JPA Hook:</b>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-bom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<name>HAPI FHIR BOM</name>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: add
|
||||
issue: 5090
|
||||
jira: SMILE-5987
|
||||
title: "Adding pointcuts for the following MDM Operations:
|
||||
MDM_CREATE_LINK, MDM_UPDATE_LINK, MDM_MERGE_GOLDEN_RESOURCES,
|
||||
MDM_LINK_HISTORY, MDM_NOT_DUPLICATE, MDM_CLEAR, MDM_SUBMIT.
|
||||
"
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ import ca.uhn.fhir.jpa.mdm.svc.candidate.TooManyCandidatesException;
|
|||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.TransactionLogMessages;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
package ca.uhn.fhir.jpa.mdm.svc;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||
|
@ -30,11 +33,15 @@ import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
|||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmEventResource;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent;
|
||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -71,64 +78,90 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
|
|||
@Autowired
|
||||
MdmPartitionHelper myMdmPartitionHelper;
|
||||
|
||||
@Autowired
|
||||
IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public IAnyResource mergeGoldenResources(
|
||||
IAnyResource theFromGoldenResource,
|
||||
IAnyResource theMergedResource,
|
||||
IAnyResource theToGoldenResource,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
String resourceType = theMdmTransactionContext.getResourceType();
|
||||
public IAnyResource mergeGoldenResources(MdmMergeGoldenResourcesParams theParams) {
|
||||
MdmTransactionContext mdmTransactionContext = theParams.getMdmTransactionContext();
|
||||
IAnyResource mergedResource = theParams.getManuallyMergedResource();
|
||||
IAnyResource fromGoldenResource = theParams.getFromGoldenResource();
|
||||
IAnyResource toGoldenResource = theParams.getToGoldenResource();
|
||||
|
||||
if (theMergedResource != null) {
|
||||
if (myGoldenResourceHelper.hasIdentifier(theMergedResource)) {
|
||||
String resourceType = mdmTransactionContext.getResourceType();
|
||||
|
||||
if (mergedResource != null) {
|
||||
if (myGoldenResourceHelper.hasIdentifier(mergedResource)) {
|
||||
throw new IllegalArgumentException(
|
||||
Msg.code(751) + "Manually merged resource can not contain identifiers");
|
||||
}
|
||||
myGoldenResourceHelper.mergeIndentifierFields(
|
||||
theFromGoldenResource, theMergedResource, theMdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeIndentifierFields(
|
||||
theToGoldenResource, theMergedResource, theMdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeIndentifierFields(fromGoldenResource, mergedResource, mdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeIndentifierFields(toGoldenResource, mergedResource, mdmTransactionContext);
|
||||
|
||||
theMergedResource.setId(theToGoldenResource.getId());
|
||||
theToGoldenResource = (IAnyResource) myMdmResourceDaoSvc
|
||||
.upsertGoldenResource(theMergedResource, resourceType)
|
||||
mergedResource.setId(toGoldenResource.getId());
|
||||
toGoldenResource = (IAnyResource) myMdmResourceDaoSvc
|
||||
.upsertGoldenResource(mergedResource, resourceType)
|
||||
.getResource();
|
||||
} else {
|
||||
myGoldenResourceHelper.mergeIndentifierFields(
|
||||
theFromGoldenResource, theToGoldenResource, theMdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeNonIdentiferFields(
|
||||
theFromGoldenResource, theToGoldenResource, theMdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeIndentifierFields(fromGoldenResource, toGoldenResource, mdmTransactionContext);
|
||||
myGoldenResourceHelper.mergeNonIdentiferFields(fromGoldenResource, toGoldenResource, mdmTransactionContext);
|
||||
// Save changes to the golden resource
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(theToGoldenResource, resourceType);
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(toGoldenResource, resourceType);
|
||||
}
|
||||
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(theFromGoldenResource, theToGoldenResource);
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(fromGoldenResource, toGoldenResource);
|
||||
|
||||
// Merge the links from the FROM to the TO resource. Clean up dangling links.
|
||||
mergeGoldenResourceLinks(
|
||||
theFromGoldenResource,
|
||||
theToGoldenResource,
|
||||
theFromGoldenResource.getIdElement(),
|
||||
theMdmTransactionContext);
|
||||
fromGoldenResource, toGoldenResource, fromGoldenResource.getIdElement(), mdmTransactionContext);
|
||||
|
||||
// Create the new REDIRECT link
|
||||
addMergeLink(theToGoldenResource, theFromGoldenResource, resourceType, theMdmTransactionContext);
|
||||
addMergeLink(toGoldenResource, fromGoldenResource, resourceType, mdmTransactionContext);
|
||||
|
||||
// Strip the golden resource tag from the now-deprecated resource.
|
||||
myMdmResourceDaoSvc.removeGoldenResourceTag(theFromGoldenResource, resourceType);
|
||||
myMdmResourceDaoSvc.removeGoldenResourceTag(fromGoldenResource, resourceType);
|
||||
|
||||
// Add the REDIRECT tag to that same deprecated resource.
|
||||
MdmResourceUtil.setGoldenResourceRedirected(theFromGoldenResource);
|
||||
MdmResourceUtil.setGoldenResourceRedirected(fromGoldenResource);
|
||||
|
||||
// Save the deprecated resource.
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(theFromGoldenResource, resourceType);
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(fromGoldenResource, resourceType);
|
||||
|
||||
log(
|
||||
theMdmTransactionContext,
|
||||
"Merged " + theFromGoldenResource.getIdElement().toVersionless() + " into "
|
||||
+ theToGoldenResource.getIdElement().toVersionless());
|
||||
return theToGoldenResource;
|
||||
mdmTransactionContext,
|
||||
"Merged " + fromGoldenResource.getIdElement().toVersionless() + " into "
|
||||
+ toGoldenResource.getIdElement().toVersionless());
|
||||
|
||||
// invoke hooks
|
||||
invokeMdmMergeGoldenResourcesHook(theParams, fromGoldenResource, toGoldenResource);
|
||||
|
||||
return toGoldenResource;
|
||||
}
|
||||
|
||||
private void invokeMdmMergeGoldenResourcesHook(
|
||||
MdmMergeGoldenResourcesParams theParams, IAnyResource fromGoldenResource, IAnyResource toGoldenResource) {
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES)) {
|
||||
// pointcut for MDM_POST_MERGE_GOLDEN_RESOURCES
|
||||
MdmMergeEvent event = new MdmMergeEvent();
|
||||
MdmEventResource from = new MdmEventResource();
|
||||
from.setId(
|
||||
fromGoldenResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
from.setResourceType(fromGoldenResource.fhirType());
|
||||
from.setIsGoldenResource(true);
|
||||
event.setFromResource(from);
|
||||
|
||||
MdmEventResource to = new MdmEventResource();
|
||||
to.setId(toGoldenResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
to.setResourceType(toGoldenResource.fhirType());
|
||||
to.setIsGoldenResource(true);
|
||||
event.setToResource(to);
|
||||
|
||||
HookParams params = new HookParams();
|
||||
params.add(MdmMergeEvent.class, event);
|
||||
params.add(RequestDetails.class, theParams.getRequestDetails());
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
package ca.uhn.fhir.jpa.mdm.svc;
|
||||
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
|
||||
/**
|
||||
* Contract for decoupling API dependency from the base / JPA modules.
|
||||
|
|
|
@ -22,6 +22,9 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
import ca.uhn.fhir.batch2.api.IJobCoordinator;
|
||||
import ca.uhn.fhir.batch2.model.JobInstanceStartRequest;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
|
||||
|
@ -32,8 +35,6 @@ import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
|
|||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmHistorySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmQuerySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
|
@ -41,9 +42,15 @@ import ca.uhn.fhir.mdm.batch2.clear.MdmClearAppCtx;
|
|||
import ca.uhn.fhir.mdm.batch2.clear.MdmClearJobParameters;
|
||||
import ca.uhn.fhir.mdm.batch2.submit.MdmSubmitAppCtx;
|
||||
import ca.uhn.fhir.mdm.batch2.submit.MdmSubmitJobParameters;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmUnduplicateGoldenResourceParams;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmClearEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmSubmitEvent;
|
||||
import ca.uhn.fhir.mdm.provider.MdmControllerHelper;
|
||||
import ca.uhn.fhir.mdm.provider.MdmControllerUtil;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
|
@ -93,24 +100,43 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
@Autowired
|
||||
IJobCoordinator myJobCoordinator;
|
||||
|
||||
@Autowired
|
||||
IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
public MdmControllerSvcImpl() {}
|
||||
|
||||
@Override
|
||||
public IAnyResource mergeGoldenResources(
|
||||
String theFromGoldenResourceId,
|
||||
String theToGoldenResourceId,
|
||||
IAnyResource theManuallyMergedGoldenResource,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
IAnyResource fromGoldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theFromGoldenResourceId);
|
||||
IAnyResource toGoldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, theToGoldenResourceId);
|
||||
public IAnyResource mergeGoldenResources(MdmMergeGoldenResourcesParams theParams) {
|
||||
if (theParams.getFromGoldenResource() == null) {
|
||||
theParams.setFromGoldenResource(myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theParams.getFromGoldenResourceId()));
|
||||
}
|
||||
IAnyResource fromGoldenResource = theParams.getFromGoldenResource();
|
||||
;
|
||||
if (theParams.getToGoldenResource() == null) {
|
||||
theParams.setToGoldenResource(myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, theParams.getToGoldenResourceId()));
|
||||
}
|
||||
IAnyResource toGoldenResource = theParams.getToGoldenResource();
|
||||
myMdmControllerHelper.validateMergeResources(fromGoldenResource, toGoldenResource);
|
||||
myMdmControllerHelper.validateSameVersion(fromGoldenResource, theFromGoldenResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(toGoldenResource, theToGoldenResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(fromGoldenResource, theParams.getFromGoldenResourceId());
|
||||
myMdmControllerHelper.validateSameVersion(toGoldenResource, theParams.getToGoldenResourceId());
|
||||
|
||||
return myGoldenResourceMergerSvc.mergeGoldenResources(
|
||||
fromGoldenResource, theManuallyMergedGoldenResource, toGoldenResource, theMdmTransactionContext);
|
||||
return myGoldenResourceMergerSvc.mergeGoldenResources(theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAnyResource updateLink(
|
||||
String theGoldenResourceId,
|
||||
String theSourceResourceId,
|
||||
String theMatchResult,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setResourceId(theSourceResourceId);
|
||||
params.setGoldenResourceId(theGoldenResourceId);
|
||||
params.setMdmContext(theMdmTransactionContext);
|
||||
params.setMatchResult(MdmMatchResultEnum.valueOf(theMatchResult));
|
||||
return updateLink(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -228,21 +254,25 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
return resultPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAnyResource updateLink(
|
||||
String theGoldenResourceId,
|
||||
String theSourceResourceId,
|
||||
String theMatchResult,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
|
||||
private void convertAndValidateParameters(MdmCreateOrUpdateParams theParams) {
|
||||
if (theParams.getGoldenResource() == null) {
|
||||
IAnyResource goldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
|
||||
ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theParams.getGoldenResourceId());
|
||||
theParams.setGoldenResource(goldenResource);
|
||||
}
|
||||
if (theParams.getSourceResource() == null) {
|
||||
IAnyResource source = myMdmControllerHelper.getLatestSourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theSourceResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(goldenResource, theGoldenResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(source, theSourceResourceId);
|
||||
ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theParams.getResourceId());
|
||||
theParams.setSourceResource(source);
|
||||
}
|
||||
myMdmControllerHelper.validateSameVersion(theParams.getGoldenResource(), theParams.getGoldenResourceId());
|
||||
myMdmControllerHelper.validateSameVersion(theParams.getSourceResource(), theParams.getResourceId());
|
||||
}
|
||||
|
||||
return myIMdmLinkUpdaterSvc.updateLink(goldenResource, source, matchResult, theMdmTransactionContext);
|
||||
@Override
|
||||
public IAnyResource updateLink(MdmCreateOrUpdateParams theParams) {
|
||||
convertAndValidateParameters(theParams);
|
||||
return myIMdmLinkUpdaterSvc.updateLink(theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,15 +281,21 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
String theSourceResourceId,
|
||||
@Nullable String theMatchResult,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
|
||||
IAnyResource goldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
|
||||
IAnyResource source = myMdmControllerHelper.getLatestSourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_CREATE_LINK_RESOURCE_ID, theSourceResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(goldenResource, theGoldenResourceId);
|
||||
myMdmControllerHelper.validateSameVersion(source, theSourceResourceId);
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setGoldenResourceId(theGoldenResourceId);
|
||||
params.setResourceId(theSourceResourceId);
|
||||
params.setMdmContext(theMdmTransactionContext);
|
||||
if (theMatchResult != null) {
|
||||
params.setMatchResult(MdmMatchResultEnum.valueOf(theMatchResult));
|
||||
}
|
||||
return createLink(params);
|
||||
}
|
||||
|
||||
return myIMdmLinkCreateSvc.createLink(goldenResource, source, matchResult, theMdmTransactionContext);
|
||||
@Override
|
||||
public IAnyResource createLink(MdmCreateOrUpdateParams theParams) {
|
||||
convertAndValidateParameters(theParams);
|
||||
|
||||
return myIMdmLinkCreateSvc.createLink(theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -269,9 +305,10 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
ServletRequestDetails theRequestDetails) {
|
||||
MdmClearJobParameters params = new MdmClearJobParameters();
|
||||
params.setResourceNames(theResourceNames);
|
||||
if (theBatchSize != null
|
||||
boolean hasBatchSize = theBatchSize != null
|
||||
&& theBatchSize.getValue() != null
|
||||
&& theBatchSize.getValue().longValue() > 0) {
|
||||
&& theBatchSize.getValue().longValue() > 0;
|
||||
if (hasBatchSize) {
|
||||
params.setBatchSize(theBatchSize.getValue().intValue());
|
||||
}
|
||||
|
||||
|
@ -287,6 +324,20 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
Batch2JobStartResponse response = myJobCoordinator.startInstance(theRequestDetails, request);
|
||||
String id = response.getInstanceId();
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_CLEAR)) {
|
||||
// MDM_CLEAR hook:
|
||||
MdmClearEvent event = new MdmClearEvent();
|
||||
event.setResourceTypes(theResourceNames);
|
||||
if (hasBatchSize) {
|
||||
event.setBatchSize(theBatchSize.getValue().longValue());
|
||||
}
|
||||
|
||||
HookParams hookParams = new HookParams();
|
||||
hookParams.add(RequestDetails.class, theRequestDetails);
|
||||
hookParams.add(MdmClearEvent.class, event);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_CLEAR, hookParams);
|
||||
}
|
||||
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myFhirContext);
|
||||
ParametersUtil.addParameterToParametersString(
|
||||
myFhirContext, retVal, ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, id);
|
||||
|
@ -297,10 +348,10 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
public IBaseParameters submitMdmSubmitJob(
|
||||
List<String> theUrls, IPrimitiveType<BigDecimal> theBatchSize, ServletRequestDetails theRequestDetails) {
|
||||
MdmSubmitJobParameters params = new MdmSubmitJobParameters();
|
||||
|
||||
if (theBatchSize != null
|
||||
boolean hasBatchSize = theBatchSize != null
|
||||
&& theBatchSize.getValue() != null
|
||||
&& theBatchSize.getValue().longValue() > 0) {
|
||||
&& theBatchSize.getValue().longValue() > 0;
|
||||
if (hasBatchSize) {
|
||||
params.setBatchSize(theBatchSize.getValue().intValue());
|
||||
}
|
||||
params.setRequestPartitionId(RequestPartitionId.allPartitions());
|
||||
|
@ -317,6 +368,22 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
IBaseParameters retVal = ParametersUtil.newInstance(myFhirContext);
|
||||
ParametersUtil.addParameterToParametersString(
|
||||
myFhirContext, retVal, ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, id);
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_SUBMIT)) {
|
||||
// MDM_SUBMIT batch submit job
|
||||
MdmSubmitEvent event = new MdmSubmitEvent();
|
||||
event.setBatchJob(true);
|
||||
event.setUrls(theUrls);
|
||||
if (hasBatchSize) {
|
||||
event.setBatchSize(theBatchSize.getValue().longValue());
|
||||
}
|
||||
|
||||
HookParams hookParams = new HookParams();
|
||||
hookParams.add(RequestDetails.class, theRequestDetails);
|
||||
hookParams.add(MdmSubmitEvent.class, event);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_SUBMIT, hookParams);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -325,12 +392,43 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
|
|||
String theGoldenResourceId,
|
||||
String theTargetGoldenResourceId,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
IAnyResource goldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
|
||||
IAnyResource target = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theTargetGoldenResourceId);
|
||||
MdmUnduplicateGoldenResourceParams params = new MdmUnduplicateGoldenResourceParams();
|
||||
params.setTargetGoldenResourceId(theTargetGoldenResourceId);
|
||||
params.setGoldenResourceId(theGoldenResourceId);
|
||||
params.setMdmContext(theMdmTransactionContext);
|
||||
|
||||
myIMdmLinkUpdaterSvc.notDuplicateGoldenResource(goldenResource, target, theMdmTransactionContext);
|
||||
unduplicateGoldenResource(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unduplicateGoldenResource(MdmUnduplicateGoldenResourceParams theParams) {
|
||||
if (theParams.getGoldenResource() == null) {
|
||||
IAnyResource goldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theParams.getGoldenResourceId());
|
||||
theParams.setGoldenResource(goldenResource);
|
||||
}
|
||||
if (theParams.getTargetGoldenResource() == null) {
|
||||
IAnyResource target = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(
|
||||
ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theParams.getTargetGoldenResourceId());
|
||||
theParams.setTargetGoldenResource(target);
|
||||
}
|
||||
|
||||
myIMdmLinkUpdaterSvc.unduplicateGoldenResource(theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAnyResource mergeGoldenResources(
|
||||
String theFromGoldenResourceId,
|
||||
String theToGoldenResourceId,
|
||||
IAnyResource theManuallyMergedGoldenResource,
|
||||
MdmTransactionContext theMdmTransactionContext) {
|
||||
MdmMergeGoldenResourcesParams params = new MdmMergeGoldenResourcesParams();
|
||||
params.setToGoldenResourceId(theToGoldenResourceId);
|
||||
params.setFromGoldenResourceId(theFromGoldenResourceId);
|
||||
params.setToGoldenResourceId(theToGoldenResourceId);
|
||||
params.setManuallyMergedResource(theManuallyMergedGoldenResource);
|
||||
params.setMdmTransactionContext(theMdmTransactionContext);
|
||||
return mergeGoldenResources(params);
|
||||
}
|
||||
|
||||
private void validateMdmQueryPermissions(
|
||||
|
|
|
@ -21,6 +21,9 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||
|
@ -31,11 +34,13 @@ import ca.uhn.fhir.mdm.api.IMdmSettings;
|
|||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -53,9 +58,11 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
|
|||
@Autowired
|
||||
FhirContext myFhirContext;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Autowired
|
||||
IIdHelperService myIdHelperService;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Autowired
|
||||
MdmLinkDaoSvc myMdmLinkDaoSvc;
|
||||
|
||||
|
@ -68,49 +75,56 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
|
|||
@Autowired
|
||||
MdmPartitionHelper myMdmPartitionHelper;
|
||||
|
||||
@Autowired
|
||||
private IMdmModelConverterSvc myModelConverter;
|
||||
|
||||
@Autowired
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Transactional
|
||||
@Override
|
||||
public IAnyResource createLink(
|
||||
IAnyResource theGoldenResource,
|
||||
IAnyResource theSourceResource,
|
||||
MdmMatchResultEnum theMatchResult,
|
||||
MdmTransactionContext theMdmContext) {
|
||||
String sourceType = myFhirContext.getResourceType(theSourceResource);
|
||||
public IAnyResource createLink(MdmCreateOrUpdateParams theParams) {
|
||||
IAnyResource sourceResource = theParams.getSourceResource();
|
||||
IAnyResource goldenResource = theParams.getGoldenResource();
|
||||
MdmMatchResultEnum matchResult = theParams.getMatchResult();
|
||||
|
||||
validateCreateLinkRequest(theGoldenResource, theSourceResource, sourceType);
|
||||
String sourceType = myFhirContext.getResourceType(sourceResource);
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
|
||||
IResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
|
||||
validateCreateLinkRequest(goldenResource, sourceResource, sourceType);
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(goldenResource);
|
||||
IResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(sourceResource);
|
||||
|
||||
// check if the golden resource and the source resource are in the same partition, throw error if not
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(theGoldenResource, theSourceResource);
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(goldenResource, sourceResource);
|
||||
|
||||
Optional<? extends IMdmLink> optionalMdmLink =
|
||||
myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
|
||||
if (optionalMdmLink.isPresent()) {
|
||||
throw new InvalidRequestException(
|
||||
Msg.code(753) + myMessageHelper.getMessageForPresentLink(theGoldenResource, theSourceResource));
|
||||
Msg.code(753) + myMessageHelper.getMessageForPresentLink(goldenResource, sourceResource));
|
||||
}
|
||||
|
||||
List<? extends IMdmLink> mdmLinks =
|
||||
myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(targetId, MdmMatchResultEnum.MATCH);
|
||||
if (mdmLinks.size() > 0 && theMatchResult == MdmMatchResultEnum.MATCH) {
|
||||
if (mdmLinks.size() > 0 && matchResult == MdmMatchResultEnum.MATCH) {
|
||||
throw new InvalidRequestException(
|
||||
Msg.code(754) + myMessageHelper.getMessageForMultipleGoldenRecords(theSourceResource));
|
||||
Msg.code(754) + myMessageHelper.getMessageForMultipleGoldenRecords(sourceResource));
|
||||
}
|
||||
|
||||
IMdmLink mdmLink = myMdmLinkDaoSvc.getOrCreateMdmLinkByGoldenResourceAndSourceResource(
|
||||
theGoldenResource, theSourceResource);
|
||||
IMdmLink mdmLink =
|
||||
myMdmLinkDaoSvc.getOrCreateMdmLinkByGoldenResourceAndSourceResource(goldenResource, sourceResource);
|
||||
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
|
||||
mdmLink.setMdmSourceType(sourceType);
|
||||
if (theMatchResult == null) {
|
||||
if (matchResult == null) {
|
||||
mdmLink.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||
} else {
|
||||
mdmLink.setMatchResult(theMatchResult);
|
||||
mdmLink.setMatchResult(matchResult);
|
||||
}
|
||||
// Add partition for the mdm link if it doesn't exist
|
||||
RequestPartitionId goldenResourcePartitionId =
|
||||
(RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||
(RequestPartitionId) goldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||
if (goldenResourcePartitionId != null
|
||||
&& goldenResourcePartitionId.hasPartitionIds()
|
||||
&& goldenResourcePartitionId.getFirstPartitionIdOrNull() != null
|
||||
|
@ -119,11 +133,20 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
|
|||
goldenResourcePartitionId.getFirstPartitionIdOrNull(),
|
||||
goldenResourcePartitionId.getPartitionDate()));
|
||||
}
|
||||
ourLog.info("Manually creating a " + theGoldenResource.getIdElement().toVersionless() + " to "
|
||||
+ theSourceResource.getIdElement().toVersionless() + " mdm link.");
|
||||
ourLog.info("Manually creating a " + goldenResource.getIdElement().toVersionless() + " to "
|
||||
+ sourceResource.getIdElement().toVersionless() + " mdm link.");
|
||||
myMdmLinkDaoSvc.save(mdmLink);
|
||||
|
||||
return theGoldenResource;
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_POST_CREATE_LINK)) {
|
||||
// pointcut for MDM_POST_CREATE_LINK
|
||||
MdmLinkEvent event = new MdmLinkEvent();
|
||||
event.addMdmLink(myModelConverter.toJson(mdmLink));
|
||||
HookParams hookParams = new HookParams();
|
||||
hookParams.add(RequestDetails.class, theParams.getRequestDetails()).add(MdmLinkEvent.class, event);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_CREATE_LINK, hookParams);
|
||||
}
|
||||
|
||||
return goldenResource;
|
||||
}
|
||||
|
||||
private void validateCreateLinkRequest(
|
||||
|
|
|
@ -23,14 +23,14 @@ import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
|||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmHistorySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmQuerySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -21,6 +21,9 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||
|
@ -32,11 +35,15 @@ import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
|||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.log.Logs;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmUnduplicateGoldenResourceParams;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
|
@ -56,9 +63,11 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
|||
@Autowired
|
||||
FhirContext myFhirContext;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Autowired
|
||||
IIdHelperService myIdHelperService;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Autowired
|
||||
MdmLinkDaoSvc myMdmLinkDaoSvc;
|
||||
|
||||
|
@ -80,52 +89,60 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
|||
@Autowired
|
||||
MdmPartitionHelper myMdmPartitionHelper;
|
||||
|
||||
@Autowired
|
||||
IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@Autowired
|
||||
private IMdmModelConverterSvc myModelConverter;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Transactional
|
||||
@Override
|
||||
public IAnyResource updateLink(
|
||||
IAnyResource theGoldenResource,
|
||||
IAnyResource theSourceResource,
|
||||
MdmMatchResultEnum theMatchResult,
|
||||
MdmTransactionContext theMdmContext) {
|
||||
String sourceType = myFhirContext.getResourceType(theSourceResource);
|
||||
public IAnyResource updateLink(MdmCreateOrUpdateParams theParams) {
|
||||
IAnyResource sourceResource = theParams.getSourceResource();
|
||||
IAnyResource goldenResource = theParams.getGoldenResource();
|
||||
MdmTransactionContext mdmContext = theParams.getMdmContext();
|
||||
MdmMatchResultEnum matchResult = theParams.getMatchResult();
|
||||
|
||||
validateUpdateLinkRequest(theGoldenResource, theSourceResource, theMatchResult, sourceType);
|
||||
String sourceType = myFhirContext.getResourceType(sourceResource);
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
|
||||
IResourcePersistentId sourceResourceId = myIdHelperService.getPidOrThrowException(theSourceResource);
|
||||
validateUpdateLinkRequest(goldenResource, sourceResource, matchResult, sourceType);
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(goldenResource);
|
||||
IResourcePersistentId sourceResourceId = myIdHelperService.getPidOrThrowException(sourceResource);
|
||||
|
||||
// check if the golden resource and the source resource are in the same partition if cross partition mdm is not
|
||||
// allowed, throw error if not
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(theGoldenResource, theSourceResource);
|
||||
myMdmPartitionHelper.validateMdmResourcesPartitionMatches(goldenResource, sourceResource);
|
||||
|
||||
Optional<? extends IMdmLink> optionalMdmLink =
|
||||
myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, sourceResourceId);
|
||||
if (optionalMdmLink.isEmpty()) {
|
||||
throw new InvalidRequestException(
|
||||
Msg.code(738) + myMessageHelper.getMessageForNoLink(theGoldenResource, theSourceResource));
|
||||
Msg.code(738) + myMessageHelper.getMessageForNoLink(goldenResource, sourceResource));
|
||||
}
|
||||
|
||||
IMdmLink mdmLink = optionalMdmLink.get();
|
||||
|
||||
validateNoMatchPresentWhenAcceptingPossibleMatch(theSourceResource, goldenResourceId, theMatchResult);
|
||||
validateNoMatchPresentWhenAcceptingPossibleMatch(sourceResource, goldenResourceId, matchResult);
|
||||
|
||||
if (mdmLink.getMatchResult() == theMatchResult) {
|
||||
ourLog.warn("MDM Link for " + theGoldenResource.getIdElement().toVersionless() + ", "
|
||||
+ theSourceResource.getIdElement().toVersionless() + " already has value " + theMatchResult
|
||||
if (mdmLink.getMatchResult() == matchResult) {
|
||||
ourLog.warn("MDM Link for " + goldenResource.getIdElement().toVersionless() + ", "
|
||||
+ sourceResource.getIdElement().toVersionless() + " already has value " + matchResult
|
||||
+ ". Nothing to do.");
|
||||
return theGoldenResource;
|
||||
return goldenResource;
|
||||
}
|
||||
|
||||
ourLog.info("Manually updating MDM Link for "
|
||||
+ theGoldenResource.getIdElement().toVersionless() + ", "
|
||||
+ theSourceResource.getIdElement().toVersionless() + " from " + mdmLink.getMatchResult() + " to "
|
||||
+ theMatchResult + ".");
|
||||
mdmLink.setMatchResult(theMatchResult);
|
||||
+ goldenResource.getIdElement().toVersionless() + ", "
|
||||
+ sourceResource.getIdElement().toVersionless() + " from " + mdmLink.getMatchResult() + " to "
|
||||
+ matchResult + ".");
|
||||
mdmLink.setMatchResult(matchResult);
|
||||
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
|
||||
|
||||
// Add partition for the mdm link if it doesn't exist
|
||||
RequestPartitionId goldenResourcePartitionId =
|
||||
(RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||
(RequestPartitionId) goldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||
if (goldenResourcePartitionId != null
|
||||
&& goldenResourcePartitionId.hasPartitionIds()
|
||||
&& goldenResourcePartitionId.getFirstPartitionIdOrNull() != null
|
||||
|
@ -136,29 +153,39 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
|||
}
|
||||
myMdmLinkDaoSvc.save(mdmLink);
|
||||
|
||||
if (theMatchResult == MdmMatchResultEnum.MATCH) {
|
||||
if (matchResult == MdmMatchResultEnum.MATCH) {
|
||||
// only apply survivorship rules in case of a match
|
||||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(
|
||||
theSourceResource, theGoldenResource, theMdmContext);
|
||||
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(sourceResource, goldenResource, mdmContext);
|
||||
}
|
||||
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(theGoldenResource, theMdmContext.getResourceType());
|
||||
if (theMatchResult == MdmMatchResultEnum.NO_MATCH) {
|
||||
myMdmResourceDaoSvc.upsertGoldenResource(goldenResource, mdmContext.getResourceType());
|
||||
if (matchResult == MdmMatchResultEnum.NO_MATCH) {
|
||||
// We need to return no match for when a Golden Resource has already been found elsewhere
|
||||
if (myMdmLinkDaoSvc
|
||||
.getMdmLinksBySourcePidAndMatchResult(sourceResourceId, MdmMatchResultEnum.MATCH)
|
||||
.isEmpty()) {
|
||||
// Need to find a new Golden Resource to link this target to
|
||||
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(theSourceResource, theMdmContext);
|
||||
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(sourceResource, mdmContext);
|
||||
}
|
||||
}
|
||||
return theGoldenResource;
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_POST_UPDATE_LINK)) {
|
||||
// pointcut for MDM_POST_UPDATE_LINK
|
||||
MdmLinkEvent event = new MdmLinkEvent();
|
||||
event.addMdmLink(myModelConverter.toJson(mdmLink));
|
||||
HookParams hookParams = new HookParams();
|
||||
hookParams.add(RequestDetails.class, theParams.getRequestDetails()).add(MdmLinkEvent.class, event);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_UPDATE_LINK, hookParams);
|
||||
}
|
||||
|
||||
return goldenResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* When updating POSSIBLE_MATCH link to a MATCH we need to validate that a MATCH to a different golden resource
|
||||
* doesn't exist, because a resource mustn't be a MATCH to more than one golden resource
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void validateNoMatchPresentWhenAcceptingPossibleMatch(
|
||||
IAnyResource theSourceResource,
|
||||
IResourcePersistentId theGoldenResourceId,
|
||||
|
@ -221,31 +248,45 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
|
|||
|
||||
@Transactional
|
||||
@Override
|
||||
public void notDuplicateGoldenResource(
|
||||
IAnyResource theGoldenResource, IAnyResource theTargetGoldenResource, MdmTransactionContext theMdmContext) {
|
||||
validateNotDuplicateGoldenResourceRequest(theGoldenResource, theTargetGoldenResource);
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void unduplicateGoldenResource(MdmUnduplicateGoldenResourceParams theParams) {
|
||||
IAnyResource goldenResource = theParams.getGoldenResource();
|
||||
IAnyResource targetGoldenResource = theParams.getTargetGoldenResource();
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
|
||||
IResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(theTargetGoldenResource);
|
||||
validateNotDuplicateGoldenResourceRequest(goldenResource, targetGoldenResource);
|
||||
|
||||
IResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(goldenResource);
|
||||
IResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(targetGoldenResource);
|
||||
|
||||
Optional<? extends IMdmLink> oMdmLink =
|
||||
myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
|
||||
if (oMdmLink.isEmpty()) {
|
||||
throw new InvalidRequestException(Msg.code(745) + "No link exists between "
|
||||
+ theGoldenResource.getIdElement().toVersionless() + " and "
|
||||
+ theTargetGoldenResource.getIdElement().toVersionless());
|
||||
+ goldenResource.getIdElement().toVersionless() + " and "
|
||||
+ targetGoldenResource.getIdElement().toVersionless());
|
||||
}
|
||||
|
||||
IMdmLink mdmLink = oMdmLink.get();
|
||||
if (!mdmLink.isPossibleDuplicate()) {
|
||||
throw new InvalidRequestException(
|
||||
Msg.code(746) + theGoldenResource.getIdElement().toVersionless() + " and "
|
||||
+ theTargetGoldenResource.getIdElement().toVersionless()
|
||||
Msg.code(746) + goldenResource.getIdElement().toVersionless() + " and "
|
||||
+ targetGoldenResource.getIdElement().toVersionless()
|
||||
+ " are not linked as POSSIBLE_DUPLICATE.");
|
||||
}
|
||||
mdmLink.setMatchResult(MdmMatchResultEnum.NO_MATCH);
|
||||
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
|
||||
myMdmLinkDaoSvc.save(mdmLink);
|
||||
IMdmLink retval = myMdmLinkDaoSvc.save(mdmLink);
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_POST_NOT_DUPLICATE)) {
|
||||
// MDM_POST_NOT_DUPLICATE hook
|
||||
MdmLinkEvent event = new MdmLinkEvent();
|
||||
event.addMdmLink(myModelConverter.toJson(retval));
|
||||
|
||||
HookParams params = new HookParams();
|
||||
params.add(RequestDetails.class, theParams.getRequestDetails());
|
||||
params.add(MdmLinkEvent.class, event);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_NOT_DUPLICATE, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,9 +21,9 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
|
||||
|
|
|
@ -133,7 +133,7 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
|
|||
@Autowired
|
||||
SearchParamRegistryImpl mySearchParamRegistry;
|
||||
@Autowired
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
@Autowired
|
||||
|
|
|
@ -5,7 +5,7 @@ import ca.uhn.fhir.interceptor.api.HookParams;
|
|||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.rest.server.TransactionLogMessages;
|
||||
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
|
|
|
@ -4,8 +4,8 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
|
|||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
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.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.List;
|
|||
public abstract class BaseProviderR4Test extends BaseMdmR4Test {
|
||||
protected MdmProviderDstu3Plus myMdmProvider;
|
||||
@Autowired
|
||||
private IMdmControllerSvc myMdmControllerSvc;
|
||||
protected IMdmControllerSvc myMdmControllerSvc;
|
||||
@Autowired
|
||||
private IMdmSubmitSvc myMdmSubmitSvc;
|
||||
@Autowired
|
||||
|
@ -56,7 +56,12 @@ public abstract class BaseProviderR4Test extends BaseMdmR4Test {
|
|||
|
||||
@BeforeEach
|
||||
public void before() throws Exception {
|
||||
myMdmProvider = new MdmProviderDstu3Plus(myFhirContext, myMdmControllerSvc, myMdmHelper, myMdmSubmitSvc, myMdmSettings);
|
||||
myMdmProvider = new MdmProviderDstu3Plus(myFhirContext,
|
||||
myMdmControllerSvc,
|
||||
myMdmHelper,
|
||||
myMdmSubmitSvc,
|
||||
myInterceptorBroadcaster,
|
||||
myMdmSettings);
|
||||
defaultScript = myMdmSettings.getScriptText();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,602 @@
|
|||
package ca.uhn.fhir.jpa.mdm.provider;
|
||||
|
||||
import ca.uhn.fhir.batch2.api.IJobCoordinator;
|
||||
import ca.uhn.fhir.batch2.model.JobInstanceStartRequest;
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
|
||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.MdmLinkHelper;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.testmodels.MDMState;
|
||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmClearEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmHistoryEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmSubmitEvent;
|
||||
import ca.uhn.fhir.mdm.provider.MdmLinkHistoryProviderDstu3Plus;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Practitioner;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
public class MdmOperationPointcutsIT extends BaseProviderR4Test {
|
||||
|
||||
/**
|
||||
* mdm link history can submit by
|
||||
* sourceids, goldenids, or both.
|
||||
* We will use this enum in the MDM_LINK_HISTORY pointcut
|
||||
* test.
|
||||
*/
|
||||
private enum LinkHistoryParameters {
|
||||
SOURCE_IDS,
|
||||
GOLDEN_IDS,
|
||||
BOTH
|
||||
}
|
||||
|
||||
/**
|
||||
* There are multiple way to do an $mdm-submit batch job.
|
||||
* This enum tracks the various ways.
|
||||
* All of them should hit our interceptor.
|
||||
*/
|
||||
private enum MdmSubmitEndpoint {
|
||||
PATIENT_INSTANCE(false,false),
|
||||
PATIENT_TYPE(true, true, false),
|
||||
PRACTITIONER_INSTANCE(false, false),
|
||||
PRACTITIONER_TYPE(true, true, false),
|
||||
RANDOM_MDM_RESOURCE(true, false),
|
||||
ALL_RESOURCES(true, false);
|
||||
|
||||
private final boolean[] myAsyncOptions;
|
||||
|
||||
private final boolean myTakesCriteria;
|
||||
|
||||
MdmSubmitEndpoint(boolean theHasCriteria, boolean... theOptions) {
|
||||
myTakesCriteria = theHasCriteria;
|
||||
myAsyncOptions = theOptions;
|
||||
}
|
||||
|
||||
public boolean[] getAsyncOptions() {
|
||||
return myAsyncOptions;
|
||||
}
|
||||
|
||||
public boolean canTakeCriteria() {
|
||||
return myTakesCriteria;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(MdmOperationPointcutsIT.class);
|
||||
|
||||
@Autowired
|
||||
private MdmLinkHelper myMdmLinkHelper;
|
||||
|
||||
@Autowired
|
||||
private IInterceptorService myInterceptorService;
|
||||
|
||||
@SpyBean
|
||||
private IJobCoordinator myJobCoordinator;
|
||||
|
||||
@SpyBean
|
||||
private IMdmSubmitSvc myMdmSubmitSvc;
|
||||
|
||||
private MdmLinkHistoryProviderDstu3Plus myLinkHistoryProvider;
|
||||
|
||||
private final List<Object> myInterceptors = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myLinkHistoryProvider = new MdmLinkHistoryProviderDstu3Plus(
|
||||
myFhirContext,
|
||||
myMdmControllerSvc,
|
||||
myInterceptorBroadcaster
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws IOException {
|
||||
super.after();
|
||||
myInterceptorService.unregisterInterceptors(myInterceptors);
|
||||
myInterceptors.clear();
|
||||
}
|
||||
|
||||
@Nested
|
||||
class MdmProviderDstu3PlusTest {
|
||||
@Test
|
||||
public void mergeGoldenResources_withInterceptor_firesHook() {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean(false);
|
||||
String inputState = """
|
||||
GP1, AUTO, POSSIBLE_DUPLICATE, GP2
|
||||
""";
|
||||
MDMState<Patient, JpaPid> state = new MDMState<>();
|
||||
state.setInputState(inputState);
|
||||
|
||||
// we won't use for validation, just setup
|
||||
myMdmLinkHelper.setup(state);
|
||||
|
||||
Patient gp1 = state.getParameter("GP1");
|
||||
Patient gp2 = state.getParameter("GP2");
|
||||
|
||||
Object intereptor = new Object() {
|
||||
@Hook(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES)
|
||||
void onUpdate(RequestDetails theDetails, MdmMergeEvent theEvent) {
|
||||
called.getAndSet(true);
|
||||
assertEquals("Patient/" + gp1.getIdPart(), theEvent.getFromResource().getId());
|
||||
assertEquals("Patient/" + gp2.getIdPart(), theEvent.getToResource().getId());
|
||||
assertTrue(theEvent.getFromResource().isGoldenResource() && theEvent.getToResource().isGoldenResource());
|
||||
}
|
||||
};
|
||||
myInterceptors.add(intereptor);
|
||||
myInterceptorService.registerInterceptor(intereptor);
|
||||
|
||||
// test
|
||||
myMdmProvider.mergeGoldenResources(
|
||||
new StringType(gp1.getId()), // from
|
||||
new StringType(gp2.getId()), // to
|
||||
null, // merged resource
|
||||
new SystemRequestDetails() // request details
|
||||
);
|
||||
|
||||
// verify
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mdmUpdate_withInterceptor_firesHook() {
|
||||
// setup
|
||||
Patient p1 = createPatient();
|
||||
Patient gp1 = createGoldenPatient();
|
||||
MdmLink link = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
|
||||
link.setLinkSource(MdmLinkSourceEnum.AUTO);
|
||||
link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
|
||||
link.setCreated(new Date());
|
||||
link.setGoldenResourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), gp1)));
|
||||
link.setSourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), p1)));
|
||||
myMdmLinkDaoSvc.save(link);
|
||||
|
||||
MdmMatchResultEnum toSave = MdmMatchResultEnum.MATCH;
|
||||
AtomicBoolean called = new AtomicBoolean(false);
|
||||
|
||||
Object intereptor = new Object() {
|
||||
@Hook(Pointcut.MDM_POST_UPDATE_LINK)
|
||||
void onUpdate(RequestDetails theDetails, MdmLinkEvent theEvent) {
|
||||
called.getAndSet(true);
|
||||
assertEquals(1, theEvent.getMdmLinks().size());
|
||||
MdmLinkJson link = theEvent.getMdmLinks().get(0);
|
||||
assertEquals(toSave, link.getMatchResult());
|
||||
assertEquals("Patient/" + p1.getIdPart(), link.getSourceId());
|
||||
assertEquals("Patient/" + gp1.getIdPart(), link.getGoldenResourceId());
|
||||
}
|
||||
};
|
||||
myInterceptors.add(intereptor);
|
||||
myInterceptorService.registerInterceptor(intereptor);
|
||||
|
||||
// test
|
||||
myMdmProvider.updateLink(
|
||||
new StringType(gp1.getId()), // golden resource id
|
||||
new StringType(p1.getId()), // resource id
|
||||
new StringType(toSave.name()), // link type
|
||||
new ServletRequestDetails() // request details
|
||||
);
|
||||
|
||||
// verify
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLink_withInterceptor_firesHook() {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean(false);
|
||||
Patient patient = createPatient();
|
||||
Patient golden = createGoldenPatient();
|
||||
MdmMatchResultEnum match = MdmMatchResultEnum.MATCH;
|
||||
|
||||
Object intereptor = new Object() {
|
||||
@Hook(Pointcut.MDM_POST_CREATE_LINK)
|
||||
void onCreate(RequestDetails theDetails, MdmLinkEvent theEvent) {
|
||||
called.getAndSet(true);
|
||||
assertEquals(1, theEvent.getMdmLinks().size());
|
||||
MdmLinkJson link = theEvent.getMdmLinks().get(0);
|
||||
assertEquals(match, link.getMatchResult());
|
||||
assertEquals("Patient/" + patient.getIdPart(), link.getSourceId());
|
||||
assertEquals("Patient/" + golden.getIdPart(), link.getGoldenResourceId());
|
||||
}
|
||||
};
|
||||
myInterceptors.add(intereptor);
|
||||
myInterceptorService.registerInterceptor(intereptor);
|
||||
|
||||
// test
|
||||
myMdmProvider.createLink(
|
||||
new StringType(golden.getId()),
|
||||
new StringType(patient.getId()),
|
||||
new StringType(match.name()),
|
||||
new ServletRequestDetails()
|
||||
);
|
||||
|
||||
// validation
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notDuplicate_withInterceptor_firesHook() {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean();
|
||||
String initialState = """
|
||||
GP1, AUTO, POSSIBLE_DUPLICATE, GP2
|
||||
""";
|
||||
MDMState<Patient, JpaPid> state = new MDMState<>();
|
||||
state.setInputState(initialState);
|
||||
|
||||
// we won't use for validation, just setup
|
||||
myMdmLinkHelper.setup(state);
|
||||
|
||||
Patient gp1 = state.getParameter("GP1");
|
||||
Patient gp2 = state.getParameter("GP2");
|
||||
|
||||
// interceptor
|
||||
Object interceptor = new Object() {
|
||||
@Hook(Pointcut.MDM_POST_NOT_DUPLICATE)
|
||||
void call(RequestDetails theRequestDetails, MdmLinkEvent theEvent) {
|
||||
called.getAndSet(true);
|
||||
|
||||
assertEquals(1, theEvent.getMdmLinks().size());
|
||||
MdmLinkJson link = theEvent.getMdmLinks().get(0);
|
||||
assertEquals("Patient/" + gp2.getIdPart(), link.getSourceId());
|
||||
assertEquals("Patient/" + gp1.getIdPart(), link.getGoldenResourceId());
|
||||
assertEquals(MdmMatchResultEnum.NO_MATCH, link.getMatchResult());
|
||||
}
|
||||
};
|
||||
myInterceptors.add(interceptor);
|
||||
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||
|
||||
// test
|
||||
myMdmProvider.notDuplicate(
|
||||
new StringType(gp1.getId()),
|
||||
new StringType(gp2.getId()),
|
||||
new ServletRequestDetails()
|
||||
);
|
||||
|
||||
// verify
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"Patient,Practitioner,Medication",
|
||||
"Patient",
|
||||
""
|
||||
})
|
||||
public void clearMdmLinks_withHook_firesInterceptor(String theResourceTypes) {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean();
|
||||
Batch2JobStartResponse response = new Batch2JobStartResponse();
|
||||
response.setInstanceId("test");
|
||||
|
||||
List<IPrimitiveType<String>> resourceTypes = new ArrayList<>();
|
||||
if (isNotBlank(theResourceTypes)) {
|
||||
String[] rts = theResourceTypes.split(",");
|
||||
for (String rt : rts) {
|
||||
resourceTypes.add(new StringType(rt));
|
||||
}
|
||||
}
|
||||
|
||||
// when
|
||||
// we don't care to actually submit the job, so we'll mock it here
|
||||
doReturn(response)
|
||||
.when(myJobCoordinator).startInstance(any(RequestDetails.class), any(JobInstanceStartRequest.class));
|
||||
|
||||
// interceptor
|
||||
Object interceptor = new Object() {
|
||||
@Hook(Pointcut.MDM_CLEAR)
|
||||
void call(RequestDetails theRequestDetails, MdmClearEvent theEvent) {
|
||||
called.set(true);
|
||||
|
||||
assertNotNull(theEvent.getResourceTypes());
|
||||
if (isNotBlank(theResourceTypes)) {
|
||||
assertEquals(resourceTypes.size(), theEvent.getResourceTypes().size());
|
||||
|
||||
for (IPrimitiveType<String> resourceName : resourceTypes) {
|
||||
assertTrue(theEvent.getResourceTypes()
|
||||
.contains(resourceName.getValueAsString()));
|
||||
}
|
||||
} else {
|
||||
// null or empty resource types means all
|
||||
// mdm resource types
|
||||
myMdmSettings.getMdmRules()
|
||||
.getMdmTypes().forEach(rtype -> {
|
||||
assertTrue(theEvent.getResourceTypes().contains(rtype));
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
myInterceptors.add(interceptor);
|
||||
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||
|
||||
// test
|
||||
myMdmProvider.clearMdmLinks(
|
||||
resourceTypes, // resource type filter
|
||||
null, // batchsize
|
||||
new ServletRequestDetails()
|
||||
);
|
||||
|
||||
// verify
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(MdmSubmitEndpoint.class)
|
||||
public void mdmSubmit_interceptor_differentPaths(MdmSubmitEndpoint theMdmSubmitEndpoint) throws InterruptedException {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean();
|
||||
Batch2JobStartResponse res = new Batch2JobStartResponse();
|
||||
res.setInstanceId("test");
|
||||
List<String> urls = new ArrayList<>();
|
||||
boolean[] asyncValue = new boolean[1];
|
||||
PointcutLatch latch = new PointcutLatch(theMdmSubmitEndpoint.name());
|
||||
|
||||
// when
|
||||
// we don't actually want to start batch jobs, so we'll mock it
|
||||
doReturn(res)
|
||||
.when(myJobCoordinator).startInstance(any(RequestDetails.class), any(JobInstanceStartRequest.class));
|
||||
doReturn(1L)
|
||||
.when(myMdmSubmitSvc).submitSourceResourceTypeToMdm(anyString(), any(), any(RequestDetails.class));
|
||||
|
||||
// use identifier because it's on almost every resource type
|
||||
StringType[] criteria = theMdmSubmitEndpoint.canTakeCriteria() ?
|
||||
new StringType[] { new StringType("identifier=true"), null }
|
||||
: new StringType[] { null };
|
||||
ServletRequestDetails request = new ServletRequestDetails();
|
||||
|
||||
// register an interceptor
|
||||
Object interceptor = new Object() {
|
||||
@Hook(Pointcut.MDM_SUBMIT)
|
||||
void call(RequestDetails theRequestDetails, MdmSubmitEvent theEvent) {
|
||||
called.set(true);
|
||||
|
||||
assertEquals(asyncValue[0], theEvent.isBatchJob());
|
||||
|
||||
String urlStr = String.join(", ", urls);
|
||||
assertEquals(urls.size(), theEvent.getUrls().size(),
|
||||
urlStr + " <-> " + String.join(", ", theEvent.getUrls()));
|
||||
for (String url : urls) {
|
||||
assertTrue(theEvent.getUrls().contains(url), "[" + urlStr + "] does not contain " + url + ".");
|
||||
}
|
||||
latch.call(1);
|
||||
}
|
||||
};
|
||||
myInterceptors.add(interceptor);
|
||||
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||
|
||||
for (StringType criterion : criteria) {
|
||||
for (boolean respondAsync : theMdmSubmitEndpoint.getAsyncOptions()) {
|
||||
ourLog.info("\nRunning test for {}; async: {}", theMdmSubmitEndpoint.name(), respondAsync);
|
||||
|
||||
// reset
|
||||
asyncValue[0] = respondAsync;
|
||||
called.set(false);
|
||||
urls.clear();
|
||||
|
||||
ServletRequestDetails req = spy(request);
|
||||
doReturn(respondAsync).when(req).isPreferRespondAsync();
|
||||
|
||||
// test
|
||||
latch.setExpectedCount(1);
|
||||
switch (theMdmSubmitEndpoint) {
|
||||
case PATIENT_INSTANCE:
|
||||
// patient must exist to do the mdm submit
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.addName()
|
||||
.setFamily("Simpson")
|
||||
.addGiven("Homer");
|
||||
long patientId = myPatientDao.create(p)
|
||||
.getId().getIdPartAsLong();
|
||||
|
||||
IdType patientIdType = new IdType("Patient/" + patientId);
|
||||
|
||||
urls.add(patientIdType.getValue());
|
||||
|
||||
myMdmProvider.mdmBatchPatientInstance(
|
||||
patientIdType,
|
||||
req
|
||||
);
|
||||
break;
|
||||
case PATIENT_TYPE:
|
||||
if (respondAsync) {
|
||||
urls.add("Patient?");
|
||||
} else {
|
||||
urls.add(createUrl("Patient", criterion));
|
||||
}
|
||||
|
||||
myMdmProvider.mdmBatchPatientType(
|
||||
criterion, // criteria
|
||||
null, // batch size
|
||||
req // request
|
||||
);
|
||||
break;
|
||||
case PRACTITIONER_INSTANCE:
|
||||
// practitioner must exist to do mdm submit
|
||||
Practitioner practitioner = new Practitioner();
|
||||
practitioner.setActive(true);
|
||||
practitioner.addName()
|
||||
.setFamily("Hibbert")
|
||||
.addGiven("Julius");
|
||||
long practitionerId = myPractitionerDao.create(practitioner)
|
||||
.getId().getIdPartAsLong();
|
||||
IdType practitionerIdType = new IdType("Practitioner/" + practitionerId);
|
||||
|
||||
urls.add(practitionerIdType.getValue());
|
||||
|
||||
myMdmProvider.mdmBatchPractitionerInstance(
|
||||
practitionerIdType,
|
||||
req
|
||||
);
|
||||
break;
|
||||
case PRACTITIONER_TYPE:
|
||||
if (respondAsync) {
|
||||
urls.add("Practitioner?");
|
||||
} else {
|
||||
urls.add(createUrl("Practitioner", criterion));
|
||||
}
|
||||
|
||||
myMdmProvider.mdmBatchPractitionerType(
|
||||
criterion, // criteria
|
||||
null, // batchsize
|
||||
req // request
|
||||
);
|
||||
break;
|
||||
case RANDOM_MDM_RESOURCE:
|
||||
// these tests use the mdm rules in:
|
||||
// resources/mdm/mdm-rules.json
|
||||
// Medication is one of the allowable mdm types
|
||||
String resourceType = "Medication";
|
||||
urls.add(createUrl(resourceType, criterion));
|
||||
myMdmProvider.mdmBatchOnAllSourceResources(
|
||||
new StringType(resourceType),
|
||||
criterion,
|
||||
null,
|
||||
req
|
||||
);
|
||||
break;
|
||||
case ALL_RESOURCES:
|
||||
myMdmSettings.getMdmRules()
|
||||
.getMdmTypes().forEach(rtype -> {
|
||||
urls.add(createUrl(rtype, criterion));
|
||||
});
|
||||
|
||||
myMdmProvider.mdmBatchOnAllSourceResources(
|
||||
null, // resource type (null is all)
|
||||
criterion, // criteria
|
||||
null, // batchsize
|
||||
req
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// verify
|
||||
latch.awaitExpected();
|
||||
assertTrue(called.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String createUrl(String theResourceType, StringType theCriteria) {
|
||||
String url = theResourceType;
|
||||
if (theCriteria != null) {
|
||||
url += "?" + theCriteria.getValueAsString();
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Nested
|
||||
class MdmLinkHistoryProviderDstu3PlusTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(LinkHistoryParameters.class)
|
||||
public void historyLinks_withPointcut_firesHook(LinkHistoryParameters theParametersToSend) {
|
||||
// setup
|
||||
AtomicBoolean called = new AtomicBoolean();
|
||||
|
||||
List<IPrimitiveType<String>> sourceIds = new ArrayList<>();
|
||||
List<IPrimitiveType<String>> goldenResourceIds = new ArrayList<>();
|
||||
|
||||
Patient p1 = createPatient();
|
||||
sourceIds.add(new StringType("Patient/" + p1.getIdPart()));
|
||||
Patient gp1 = createGoldenPatient();
|
||||
goldenResourceIds.add(new StringType("Patient/" + gp1.getIdPart()));
|
||||
MdmLink link = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
|
||||
link.setLinkSource(MdmLinkSourceEnum.AUTO);
|
||||
link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
|
||||
link.setCreated(new Date());
|
||||
link.setGoldenResourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), gp1)));
|
||||
link.setSourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), p1)));
|
||||
myMdmLinkDaoSvc.save(link);
|
||||
|
||||
// save a change
|
||||
link.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||
myMdmLinkDaoSvc.save(link);
|
||||
|
||||
// interceptor
|
||||
Object interceptor = new Object() {
|
||||
@Hook(Pointcut.MDM_POST_LINK_HISTORY)
|
||||
void onHistory(RequestDetails theRequestDetails, MdmHistoryEvent theEvent) {
|
||||
called.getAndSet(true);
|
||||
|
||||
List<MdmLinkWithRevisionJson> history = theEvent.getMdmLinkRevisions();
|
||||
List<String> gids = theEvent.getGoldenResourceIds();
|
||||
List<String> sids = theEvent.getSourceIds();
|
||||
|
||||
if (theParametersToSend == LinkHistoryParameters.SOURCE_IDS) {
|
||||
assertTrue(gids.isEmpty());
|
||||
} else if (theParametersToSend == LinkHistoryParameters.GOLDEN_IDS) {
|
||||
assertTrue(sids.isEmpty());
|
||||
} else {
|
||||
assertFalse(sids.isEmpty() && gids.isEmpty());
|
||||
}
|
||||
|
||||
assertFalse(history.isEmpty());
|
||||
assertEquals(2, history.size());
|
||||
}
|
||||
};
|
||||
myInterceptors.add(interceptor);
|
||||
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||
|
||||
// test
|
||||
List<IPrimitiveType<String>> sourceIdsToSend = theParametersToSend != LinkHistoryParameters.GOLDEN_IDS ? sourceIds : new ArrayList<>();
|
||||
List<IPrimitiveType<String>> goldenIdsToSend = theParametersToSend != LinkHistoryParameters.SOURCE_IDS ? goldenResourceIds : new ArrayList<>();
|
||||
IBaseParameters retval = myLinkHistoryProvider.historyLinks(
|
||||
goldenIdsToSend,
|
||||
sourceIdsToSend,
|
||||
new ServletRequestDetails()
|
||||
);
|
||||
|
||||
// verify
|
||||
assertTrue(called.get());
|
||||
assertFalse(retval.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.jpa.mdm.provider.BaseLinkR4Test;
|
|||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.test.Batch2JobHelper;
|
||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmQuerySearchParameters;
|
||||
|
|
|
@ -13,7 +13,9 @@ import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
|||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.interceptor.IMdmStorageInterceptor;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.TransactionLogMessages;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -107,11 +109,15 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
|
|||
assertEquals(0, redirectLinkCount());
|
||||
Patient from = theFlipToAndFromGoldenResources ? myToGoldenPatient : myFromGoldenPatient;
|
||||
Patient to = theFlipToAndFromGoldenResources ? myFromGoldenPatient : myToGoldenPatient;
|
||||
|
||||
MdmMergeGoldenResourcesParams params = new MdmMergeGoldenResourcesParams();
|
||||
params.setFromGoldenResource(from);
|
||||
params.setToGoldenResource(to);
|
||||
params.setMdmTransactionContext(createMdmContext());
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
|
||||
Patient retval = (Patient) myGoldenResourceMergerSvc.mergeGoldenResources(
|
||||
from,
|
||||
null,
|
||||
to,
|
||||
createMdmContext()
|
||||
params
|
||||
);
|
||||
assertEquals(1, redirectLinkCount());
|
||||
return retval;
|
||||
|
@ -214,8 +220,15 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
|
|||
|
||||
MdmTransactionContext ctx = createMdmContext();
|
||||
ctx.setRestOperation(MdmTransactionContext.OperationType.MANUAL_MERGE_GOLDEN_RESOURCES);
|
||||
|
||||
MdmMergeGoldenResourcesParams params = new MdmMergeGoldenResourcesParams();
|
||||
params.setFromGoldenResource(myFromGoldenPatient);
|
||||
params.setManuallyMergedResource(manuallyMergedPatient);
|
||||
params.setToGoldenResource(myToGoldenPatient);
|
||||
params.setMdmTransactionContext(ctx);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
Patient mergedSourcePatient = (Patient) myGoldenResourceMergerSvc
|
||||
.mergeGoldenResources(myFromGoldenPatient, manuallyMergedPatient, myToGoldenPatient, ctx);
|
||||
.mergeGoldenResources(params);
|
||||
|
||||
HumanName returnedName = mergedSourcePatient.getNameFirstRep();
|
||||
assertEquals("TestGiven TestFamily", returnedName.getNameAsSingleString());
|
||||
|
@ -243,11 +256,13 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
|
|||
}
|
||||
|
||||
private Patient mergeGoldenResources(Patient theFrom, Patient theTo) {
|
||||
MdmMergeGoldenResourcesParams params = new MdmMergeGoldenResourcesParams();
|
||||
params.setFromGoldenResource(theFrom);
|
||||
params.setToGoldenResource(theTo);
|
||||
params.setMdmTransactionContext(createMdmContext());
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
Patient retval = (Patient) myGoldenResourceMergerSvc.mergeGoldenResources(
|
||||
theFrom,
|
||||
null,
|
||||
theTo,
|
||||
createMdmContext()
|
||||
params
|
||||
);
|
||||
assertEquals(1, redirectLinkCount());
|
||||
return retval;
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
package ca.uhn.fhir.jpa.mdm.svc;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
|
||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -36,8 +39,10 @@ class MdmLinkCreateSvcImplTest {
|
|||
@SuppressWarnings("unused")
|
||||
@Spy
|
||||
FhirContext myFhirContext = FhirContext.forR4();
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Mock
|
||||
IIdHelperService myIdHelperService;
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Mock
|
||||
MdmLinkDaoSvc myMdmLinkDaoSvc;
|
||||
@Mock
|
||||
|
@ -47,9 +52,16 @@ class MdmLinkCreateSvcImplTest {
|
|||
@Mock
|
||||
MdmPartitionHelper myMdmPartitionHelper;
|
||||
|
||||
@Mock
|
||||
IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@Mock
|
||||
IMdmModelConverterSvc myIMdmModelConverterSvc;
|
||||
|
||||
@InjectMocks
|
||||
MdmLinkCreateSvcImpl myMdmLinkCreateSvc = new MdmLinkCreateSvcImpl();
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Test
|
||||
public void testCreateLink() {
|
||||
ArgumentCaptor<IMdmLink> mdmLinkCaptor = ArgumentCaptor.forClass(IMdmLink.class);
|
||||
|
@ -63,7 +75,13 @@ class MdmLinkCreateSvcImplTest {
|
|||
Patient sourcePatient = new Patient();
|
||||
MdmTransactionContext ctx = new MdmTransactionContext();
|
||||
|
||||
myMdmLinkCreateSvc.createLink(goldenPatient, sourcePatient, MdmMatchResultEnum.MATCH, ctx);
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setGoldenResource(goldenPatient);
|
||||
params.setSourceResource(sourcePatient);
|
||||
params.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||
params.setMdmContext(ctx);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
myMdmLinkCreateSvc.createLink(params);
|
||||
|
||||
IMdmLink mdmLink = mdmLinkCaptor.getValue();
|
||||
|
||||
|
@ -72,6 +90,7 @@ class MdmLinkCreateSvcImplTest {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
JpaPid goldenId = JpaPid.fromId(1L);
|
||||
|
|
|
@ -6,8 +6,8 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
|||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmHistorySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
@ -3,14 +3,13 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
import ca.uhn.fhir.jpa.mdm.helper.MdmLinkHelper;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
|
||||
import ca.uhn.fhir.mdm.util.MessageHelper;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -18,10 +17,8 @@ import org.hl7.fhir.r4.model.Patient;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -63,12 +60,21 @@ class MdmLinkUpdaterSvcImplIT extends BaseMdmR4Test {
|
|||
Patient patientC = createPatientFromJsonInputFileWithPossibleMatches( List.of(goldenA, goldenB) );
|
||||
|
||||
MdmTransactionContext mdmTransactionContext = getPatientUpdateLinkContext();
|
||||
// update POSSIBLE_MATCH Patient C -> GR A to MATCH (should work OK)
|
||||
myMdmLinkUpdaterSvc.updateLink(goldenA, patientC, MdmMatchResultEnum.MATCH, mdmTransactionContext);
|
||||
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setMdmContext(mdmTransactionContext);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
params.setGoldenResource(goldenA);
|
||||
params.setSourceResource(patientC);
|
||||
params.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||
|
||||
// update POSSIBLE_MATCH Patient C -> GR A to MATCH (should work OK)
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
|
||||
params.setGoldenResource(goldenB);
|
||||
// update POSSIBLE_MATCH Patient C -> GR B to MATCH (should throw exception)
|
||||
InvalidRequestException thrown = assertThrows(InvalidRequestException.class,
|
||||
() -> myMdmLinkUpdaterSvc.updateLink(goldenB, patientC, MdmMatchResultEnum.MATCH, mdmTransactionContext));
|
||||
() -> myMdmLinkUpdaterSvc.updateLink(params));
|
||||
|
||||
String expectedExceptionMessage = Msg.code(2218) + myMessageHelper.getMessageForAlreadyAcceptedLink(goldenA, patientC);
|
||||
assertEquals(expectedExceptionMessage, thrown.getMessage());
|
||||
|
@ -88,11 +94,21 @@ class MdmLinkUpdaterSvcImplIT extends BaseMdmR4Test {
|
|||
Patient patientC = createPatientFromJsonInputFileWithPossibleMatches( List.of(goldenA, goldenB) );
|
||||
MdmTransactionContext mdmTransactionContext = getPatientUpdateLinkContext();
|
||||
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setGoldenResource(goldenA);
|
||||
params.setSourceResource(patientC);
|
||||
params.setMdmContext(mdmTransactionContext);
|
||||
params.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
|
||||
// update POSSIBLE_MATCH Patient C -> GR A to MATCH (should work OK)
|
||||
myMdmLinkUpdaterSvc.updateLink(goldenA, patientC, MdmMatchResultEnum.MATCH, mdmTransactionContext);
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
|
||||
params.setMatchResult(MdmMatchResultEnum.NO_MATCH);
|
||||
params.setGoldenResource(goldenB);
|
||||
|
||||
// update POSSIBLE_MATCH Patient C -> GR B to NO_MATCH (should work OK)
|
||||
myMdmLinkUpdaterSvc.updateLink(goldenB, patientC, MdmMatchResultEnum.NO_MATCH, mdmTransactionContext);
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
}
|
||||
|
||||
private Patient createPatientFromJsonInputFileWithPossibleMatches(List<Patient> theGoldens) throws Exception {
|
||||
|
|
|
@ -5,7 +5,9 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
|||
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -41,7 +43,13 @@ class MdmLinkUpdaterSvcImplTest extends BaseMdmR4Test {
|
|||
|
||||
MdmTransactionContext mdmCtx = buildUpdateLinkMdmTransactionContext();
|
||||
|
||||
myMdmLinkUpdaterSvc.updateLink(originalJaneGolden, jane, NO_MATCH, mdmCtx);
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setMdmContext(mdmCtx);
|
||||
params.setGoldenResource(originalJaneGolden);
|
||||
params.setSourceResource(jane);
|
||||
params.setMatchResult(NO_MATCH);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
Patient newJaneGolden = getGoldenResourceFromTargetResource(jane);
|
||||
|
||||
assertNotEquals(newJaneGolden.getId(), originalJaneGolden.getId());
|
||||
|
@ -83,7 +91,13 @@ class MdmLinkUpdaterSvcImplTest extends BaseMdmR4Test {
|
|||
|
||||
myMdmSettings.getMdmRules().setVersion("2");
|
||||
|
||||
myMdmLinkUpdaterSvc.updateLink(goldenPatient, patient1, MATCH, mdmCtx);
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
params.setGoldenResource(goldenPatient);
|
||||
params.setSourceResource(patient1);
|
||||
params.setMatchResult(MATCH);
|
||||
params.setMdmContext(mdmCtx);
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
|
||||
final List<MdmLink> targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
|
||||
assertFalse(targets.isEmpty());
|
||||
|
|
|
@ -20,11 +20,13 @@ import ca.uhn.fhir.mdm.blocklist.json.BlockListJson;
|
|||
import ca.uhn.fhir.mdm.blocklist.json.BlockListRuleJson;
|
||||
import ca.uhn.fhir.mdm.blocklist.svc.IBlockListRuleProvider;
|
||||
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
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.mdm.util.MdmResourceUtil;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -661,7 +663,13 @@ public class MdmMatchLinkSvcTest {
|
|||
Patient originalJaneGolden = getGoldenResourceFromTargetResource(jane);
|
||||
|
||||
MdmTransactionContext mdmCtx = buildUpdateLinkMdmTransactionContext();
|
||||
myMdmLinkUpdaterSvc.updateLink(originalPaulGolden, paul, NO_MATCH, mdmCtx);
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setGoldenResource(originalPaulGolden);
|
||||
params.setSourceResource(paul);
|
||||
params.setMatchResult(NO_MATCH);
|
||||
params.setRequestDetails(new SystemRequestDetails());
|
||||
params.setMdmContext(mdmCtx);
|
||||
myMdmLinkUpdaterSvc.updateLink(params);
|
||||
|
||||
clearExternalEIDs(paul);
|
||||
addExternalEID(paul, EID_2);
|
||||
|
|
|
@ -4,8 +4,8 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
|
|||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
import ca.uhn.fhir.jpa.model.entity.EnversRevision;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
package ca.uhn.fhir.mdm.api;
|
||||
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public interface IGoldenResourceMergerSvc {
|
||||
|
@ -32,9 +32,5 @@ public interface IGoldenResourceMergerSvc {
|
|||
* @param theToGoldenResource the golden resource we are merging to
|
||||
* @return updated theToGoldenResource with the merged fields and links.
|
||||
*/
|
||||
IAnyResource mergeGoldenResources(
|
||||
IAnyResource theFromGoldenResource,
|
||||
IAnyResource theManuallyMergedResource,
|
||||
IAnyResource theToGoldenResource,
|
||||
MdmTransactionContext theMdmTransactionContext);
|
||||
IAnyResource mergeGoldenResources(MdmMergeGoldenResourcesParams theParams);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,12 @@
|
|||
package ca.uhn.fhir.mdm.api;
|
||||
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmUnduplicateGoldenResourceParams;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -82,29 +87,62 @@ public interface IMdmControllerSvc {
|
|||
RequestDetails theRequestDetails,
|
||||
String theRequestResourceType);
|
||||
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
void notDuplicateGoldenResource(
|
||||
String theGoldenResourceId,
|
||||
String theTargetGoldenResourceId,
|
||||
MdmTransactionContext theMdmTransactionContext);
|
||||
|
||||
default void unduplicateGoldenResource(MdmUnduplicateGoldenResourceParams theParams) {
|
||||
notDuplicateGoldenResource(
|
||||
theParams.getGoldenResourceId(), theParams.getTargetGoldenResourceId(), theParams.getMdmContext());
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
IAnyResource mergeGoldenResources(
|
||||
String theFromGoldenResourceId,
|
||||
String theToGoldenResourceId,
|
||||
IAnyResource theManuallyMergedGoldenResource,
|
||||
MdmTransactionContext theMdmTransactionContext);
|
||||
|
||||
default IAnyResource mergeGoldenResources(MdmMergeGoldenResourcesParams theParams) {
|
||||
return mergeGoldenResources(
|
||||
theParams.getFromGoldenResourceId(),
|
||||
theParams.getToGoldenResourceId(),
|
||||
theParams.getManuallyMergedResource(),
|
||||
theParams.getMdmTransactionContext());
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
IAnyResource updateLink(
|
||||
String theGoldenResourceId,
|
||||
String theSourceResourceId,
|
||||
String theMatchResult,
|
||||
MdmTransactionContext theMdmTransactionContext);
|
||||
|
||||
default IAnyResource updateLink(MdmCreateOrUpdateParams theParams) {
|
||||
String matchResult = theParams.getMatchResult() == null
|
||||
? null
|
||||
: theParams.getMatchResult().name();
|
||||
return updateLink(
|
||||
theParams.getGoldenResourceId(), theParams.getResourceId(), matchResult, theParams.getMdmContext());
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
IAnyResource createLink(
|
||||
String theGoldenResourceId,
|
||||
String theSourceResourceId,
|
||||
@Nullable String theMatchResult,
|
||||
MdmTransactionContext theMdmTransactionContext);
|
||||
|
||||
default IAnyResource createLink(MdmCreateOrUpdateParams theParams) {
|
||||
String matchResult = theParams.getMatchResult() == null
|
||||
? null
|
||||
: theParams.getMatchResult().name();
|
||||
return createLink(
|
||||
theParams.getGoldenResourceId(), theParams.getResourceId(), matchResult, theParams.getMdmContext());
|
||||
}
|
||||
|
||||
IBaseParameters submitMdmClearJob(
|
||||
List<String> theResourceNames,
|
||||
IPrimitiveType<BigDecimal> theBatchSize,
|
||||
|
|
|
@ -19,13 +19,9 @@
|
|||
*/
|
||||
package ca.uhn.fhir.mdm.api;
|
||||
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public interface IMdmLinkCreateSvc {
|
||||
IAnyResource createLink(
|
||||
IAnyResource theGoldenResource,
|
||||
IAnyResource theSourceResource,
|
||||
MdmMatchResultEnum theMatchResult,
|
||||
MdmTransactionContext theMdmContext);
|
||||
IAnyResource createLink(MdmCreateOrUpdateParams theParams);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ package ca.uhn.fhir.mdm.api;
|
|||
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
|
|
|
@ -19,16 +19,12 @@
|
|||
*/
|
||||
package ca.uhn.fhir.mdm.api;
|
||||
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmUnduplicateGoldenResourceParams;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public interface IMdmLinkUpdaterSvc {
|
||||
IAnyResource updateLink(
|
||||
IAnyResource theGoldenResource,
|
||||
IAnyResource theSourceResource,
|
||||
MdmMatchResultEnum theMatchResult,
|
||||
MdmTransactionContext theMdmContext);
|
||||
IAnyResource updateLink(MdmCreateOrUpdateParams theParams);
|
||||
|
||||
void notDuplicateGoldenResource(
|
||||
IAnyResource theGoldenResource, IAnyResource theTargetGoldenResource, MdmTransactionContext theMdmContext);
|
||||
void unduplicateGoldenResource(MdmUnduplicateGoldenResourceParams theParams);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public interface IMdmSubmitSvc {
|
|||
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for MDM processing.
|
||||
* @return the number of resources submitted for MDM processing.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
long submitPractitionerTypeToMdm(String theCriteria, RequestDetails theRequestDetails);
|
||||
|
||||
/**
|
||||
|
@ -63,6 +64,7 @@ public interface IMdmSubmitSvc {
|
|||
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for MDM processing.
|
||||
* @return the number of resources submitted for MDM processing.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "6.8.0")
|
||||
long submitPatientTypeToMdm(String theCriteria, RequestDetails theRequestDetails);
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
package ca.uhn.fhir.mdm.api.paging;
|
||||
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package ca.uhn.fhir.mdm.model;
|
||||
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public class MdmCreateOrUpdateParams {
|
||||
/**
|
||||
* The golden resource id
|
||||
*/
|
||||
private String myGoldenResourceId;
|
||||
|
||||
/**
|
||||
* The golden resource to update for the link.
|
||||
*/
|
||||
private IAnyResource myGoldenResource;
|
||||
|
||||
/**
|
||||
* The source id.
|
||||
*/
|
||||
private String myResourceId;
|
||||
|
||||
/**
|
||||
* The source resource linked to the golden resource
|
||||
*/
|
||||
private IAnyResource mySourceResource;
|
||||
/**
|
||||
* Match result to update the link to.
|
||||
*/
|
||||
private MdmMatchResultEnum myMatchResult;
|
||||
/**
|
||||
* The context.
|
||||
*/
|
||||
private MdmTransactionContext myMdmContext;
|
||||
|
||||
/**
|
||||
* The request details.
|
||||
*/
|
||||
private RequestDetails myRequestDetails;
|
||||
|
||||
public String getGoldenResourceId() {
|
||||
return myGoldenResourceId;
|
||||
}
|
||||
|
||||
public void setGoldenResourceId(String theGoldenResourceId) {
|
||||
myGoldenResourceId = theGoldenResourceId;
|
||||
}
|
||||
|
||||
public String getResourceId() {
|
||||
return myResourceId;
|
||||
}
|
||||
|
||||
public void setResourceId(String theResourceId) {
|
||||
myResourceId = theResourceId;
|
||||
}
|
||||
|
||||
public IAnyResource getGoldenResource() {
|
||||
return myGoldenResource;
|
||||
}
|
||||
|
||||
public void setGoldenResource(IAnyResource theGoldenResource) {
|
||||
myGoldenResource = theGoldenResource;
|
||||
}
|
||||
|
||||
public IAnyResource getSourceResource() {
|
||||
return mySourceResource;
|
||||
}
|
||||
|
||||
public void setSourceResource(IAnyResource theSourceResource) {
|
||||
mySourceResource = theSourceResource;
|
||||
}
|
||||
|
||||
public MdmMatchResultEnum getMatchResult() {
|
||||
return myMatchResult;
|
||||
}
|
||||
|
||||
public void setMatchResult(MdmMatchResultEnum theMatchResult) {
|
||||
myMatchResult = theMatchResult;
|
||||
}
|
||||
|
||||
public MdmTransactionContext getMdmContext() {
|
||||
return myMdmContext;
|
||||
}
|
||||
|
||||
public void setMdmContext(MdmTransactionContext theMdmContext) {
|
||||
myMdmContext = theMdmContext;
|
||||
}
|
||||
|
||||
public RequestDetails getRequestDetails() {
|
||||
return myRequestDetails;
|
||||
}
|
||||
|
||||
public void setRequestDetails(RequestDetails theRequestDetails) {
|
||||
myRequestDetails = theRequestDetails;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package ca.uhn.fhir.mdm.model;
|
||||
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public class MdmMergeGoldenResourcesParams {
|
||||
private String myFromGoldenResourceId;
|
||||
private IAnyResource myFromGoldenResource;
|
||||
private String myToGoldenResourceId;
|
||||
|
||||
private IAnyResource myManuallyMergedResource;
|
||||
|
||||
private IAnyResource myToGoldenResource;
|
||||
|
||||
private MdmTransactionContext myMdmTransactionContext;
|
||||
|
||||
private RequestDetails myRequestDetails;
|
||||
|
||||
public String getFromGoldenResourceId() {
|
||||
return myFromGoldenResourceId;
|
||||
}
|
||||
|
||||
public void setFromGoldenResourceId(String theTheFromGoldenResourceId) {
|
||||
myFromGoldenResourceId = theTheFromGoldenResourceId;
|
||||
}
|
||||
|
||||
public String getToGoldenResourceId() {
|
||||
return myToGoldenResourceId;
|
||||
}
|
||||
|
||||
public void setToGoldenResourceId(String theTheToGoldenResourceId) {
|
||||
myToGoldenResourceId = theTheToGoldenResourceId;
|
||||
}
|
||||
|
||||
public IAnyResource getFromGoldenResource() {
|
||||
return myFromGoldenResource;
|
||||
}
|
||||
|
||||
public void setFromGoldenResource(IAnyResource theFromGoldenResource) {
|
||||
myFromGoldenResource = theFromGoldenResource;
|
||||
}
|
||||
|
||||
public IAnyResource getManuallyMergedResource() {
|
||||
return myManuallyMergedResource;
|
||||
}
|
||||
|
||||
public void setManuallyMergedResource(IAnyResource theManuallyMergedResource) {
|
||||
myManuallyMergedResource = theManuallyMergedResource;
|
||||
}
|
||||
|
||||
public IAnyResource getToGoldenResource() {
|
||||
return myToGoldenResource;
|
||||
}
|
||||
|
||||
public void setToGoldenResource(IAnyResource theToGoldenResource) {
|
||||
myToGoldenResource = theToGoldenResource;
|
||||
}
|
||||
|
||||
public MdmTransactionContext getMdmTransactionContext() {
|
||||
return myMdmTransactionContext;
|
||||
}
|
||||
|
||||
public void setMdmTransactionContext(MdmTransactionContext theMdmTransactionContext) {
|
||||
myMdmTransactionContext = theMdmTransactionContext;
|
||||
}
|
||||
|
||||
public RequestDetails getRequestDetails() {
|
||||
return myRequestDetails;
|
||||
}
|
||||
|
||||
public void setRequestDetails(RequestDetails theRequestDetails) {
|
||||
myRequestDetails = theRequestDetails;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package ca.uhn.fhir.mdm.model;
|
||||
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
||||
public class MdmUnduplicateGoldenResourceParams {
|
||||
|
||||
private String myGoldenResourceId;
|
||||
|
||||
private IAnyResource myGoldenResource;
|
||||
|
||||
private String myTargetGoldenResourceId;
|
||||
|
||||
private IAnyResource myTargetGoldenResource;
|
||||
|
||||
private MdmTransactionContext myMdmContext;
|
||||
|
||||
private RequestDetails myRequestDetails;
|
||||
|
||||
public IAnyResource getGoldenResource() {
|
||||
return myGoldenResource;
|
||||
}
|
||||
|
||||
public void setGoldenResource(IAnyResource theGoldenResource) {
|
||||
myGoldenResource = theGoldenResource;
|
||||
}
|
||||
|
||||
public IAnyResource getTargetGoldenResource() {
|
||||
return myTargetGoldenResource;
|
||||
}
|
||||
|
||||
public void setTargetGoldenResource(IAnyResource theTargetGoldenResource) {
|
||||
myTargetGoldenResource = theTargetGoldenResource;
|
||||
}
|
||||
|
||||
public MdmTransactionContext getMdmContext() {
|
||||
return myMdmContext;
|
||||
}
|
||||
|
||||
public void setMdmContext(MdmTransactionContext theMdmContext) {
|
||||
myMdmContext = theMdmContext;
|
||||
}
|
||||
|
||||
public RequestDetails getRequestDetails() {
|
||||
return myRequestDetails;
|
||||
}
|
||||
|
||||
public void setRequestDetails(RequestDetails theRequestDetails) {
|
||||
myRequestDetails = theRequestDetails;
|
||||
}
|
||||
|
||||
public String getGoldenResourceId() {
|
||||
return myGoldenResourceId;
|
||||
}
|
||||
|
||||
public void setGoldenResourceId(String theGoldenResourceId) {
|
||||
myGoldenResourceId = theGoldenResourceId;
|
||||
}
|
||||
|
||||
public String getTargetGoldenResourceId() {
|
||||
return myTargetGoldenResourceId;
|
||||
}
|
||||
|
||||
public void setTargetGoldenResourceId(String theTargetGoldenResourceId) {
|
||||
myTargetGoldenResourceId = theTargetGoldenResourceId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MdmClearEvent implements IModelJson {
|
||||
|
||||
@JsonProperty("resourceTypes")
|
||||
private List<String> myResourceTypes;
|
||||
|
||||
/**
|
||||
* True if this submit was done asynchronously
|
||||
* (ie, was submitted as a batch job).
|
||||
* False if submitted directly to mdm.
|
||||
*/
|
||||
@JsonProperty("batchSize")
|
||||
private Long myBatchSize;
|
||||
|
||||
public Long getBatchSize() {
|
||||
return myBatchSize;
|
||||
}
|
||||
|
||||
public void setBatchSize(Long theBatchSize) {
|
||||
myBatchSize = theBatchSize;
|
||||
}
|
||||
|
||||
public List<String> getResourceTypes() {
|
||||
if (myResourceTypes == null) {
|
||||
myResourceTypes = new ArrayList<>();
|
||||
}
|
||||
return myResourceTypes;
|
||||
}
|
||||
|
||||
public void setResourceTypes(List<String> theResourceTypes) {
|
||||
myResourceTypes = theResourceTypes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class MdmEventResource implements IModelJson {
|
||||
/**
|
||||
* The id of the resource that's part of this event.
|
||||
*/
|
||||
@JsonProperty("id")
|
||||
private String myId;
|
||||
|
||||
/**
|
||||
* The resource type.
|
||||
*/
|
||||
@JsonProperty("resourceType")
|
||||
private String myResourceType;
|
||||
|
||||
/**
|
||||
* True if this is a golden resource; false otherwise.
|
||||
*/
|
||||
@JsonProperty("isGoldenResource")
|
||||
private boolean myIsGoldenResource;
|
||||
|
||||
public String getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public void setId(String theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return myResourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(String theResourceType) {
|
||||
myResourceType = theResourceType;
|
||||
}
|
||||
|
||||
public boolean isGoldenResource() {
|
||||
return myIsGoldenResource;
|
||||
}
|
||||
|
||||
public void setIsGoldenResource(boolean theGoldenResource) {
|
||||
myIsGoldenResource = theGoldenResource;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MdmHistoryEvent implements IModelJson {
|
||||
|
||||
/**
|
||||
* List of golden resource ids queried.
|
||||
* Can be empty.
|
||||
*/
|
||||
@JsonProperty("goldenResourceIds")
|
||||
private List<String> myGoldenResourceIds;
|
||||
|
||||
/**
|
||||
* List of source ids queried.
|
||||
* Can be empty.
|
||||
*/
|
||||
@JsonProperty("sourceIds")
|
||||
private List<String> mySourceIds;
|
||||
|
||||
/**
|
||||
* The associated link revisions returned from the search.
|
||||
*/
|
||||
@JsonProperty("mdmLinkRevisions")
|
||||
private List<MdmLinkWithRevisionJson> myMdmLinkRevisions;
|
||||
|
||||
public List<String> getGoldenResourceIds() {
|
||||
if (myGoldenResourceIds == null) {
|
||||
myGoldenResourceIds = new ArrayList<>();
|
||||
}
|
||||
return myGoldenResourceIds;
|
||||
}
|
||||
|
||||
public void setGoldenResourceIds(List<String> theGoldenResourceIds) {
|
||||
myGoldenResourceIds = theGoldenResourceIds;
|
||||
}
|
||||
|
||||
public List<String> getSourceIds() {
|
||||
if (mySourceIds == null) {
|
||||
mySourceIds = new ArrayList<>();
|
||||
}
|
||||
return mySourceIds;
|
||||
}
|
||||
|
||||
public void setSourceIds(List<String> theSourceIds) {
|
||||
mySourceIds = theSourceIds;
|
||||
}
|
||||
|
||||
public List<MdmLinkWithRevisionJson> getMdmLinkRevisions() {
|
||||
if (myMdmLinkRevisions == null) {
|
||||
myMdmLinkRevisions = new ArrayList<>();
|
||||
}
|
||||
return myMdmLinkRevisions;
|
||||
}
|
||||
|
||||
public void setMdmLinkRevisions(List<MdmLinkWithRevisionJson> theMdmLinkRevisions) {
|
||||
myMdmLinkRevisions = theMdmLinkRevisions;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.mdm.api;
|
||||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
|
|
@ -17,8 +17,10 @@
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.mdm.api;
|
||||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.mdm.api;
|
||||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
/*-
|
||||
* #%L
|
|
@ -0,0 +1,26 @@
|
|||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
|
||||
public class MdmMergeEvent implements IModelJson {
|
||||
|
||||
private MdmEventResource myFromResource;
|
||||
|
||||
private MdmEventResource myToResource;
|
||||
|
||||
public MdmEventResource getFromResource() {
|
||||
return myFromResource;
|
||||
}
|
||||
|
||||
public void setFromResource(MdmEventResource theFromResource) {
|
||||
myFromResource = theFromResource;
|
||||
}
|
||||
|
||||
public MdmEventResource getToResource() {
|
||||
return myToResource;
|
||||
}
|
||||
|
||||
public void setToResource(MdmEventResource theToResource) {
|
||||
myToResource = theToResource;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||
|
||||
import ca.uhn.fhir.model.api.IModelJson;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MdmSubmitEvent implements IModelJson {
|
||||
|
||||
/**
|
||||
* Batch size; only applicable if this is a batch job
|
||||
*/
|
||||
@JsonProperty("batchSize")
|
||||
private Long myBatchSize;
|
||||
|
||||
/**
|
||||
* The search/resource urls used in this job
|
||||
*/
|
||||
@JsonProperty("urls")
|
||||
private List<String> myUrls;
|
||||
|
||||
/**
|
||||
* True if this submit was done asynchronously
|
||||
* (ie, was submitted as a batch job).
|
||||
* False if submitted directly to mdm.
|
||||
*/
|
||||
@JsonProperty("batch_job")
|
||||
private boolean myIsBatchJob;
|
||||
|
||||
public Long getBatchSize() {
|
||||
return myBatchSize;
|
||||
}
|
||||
|
||||
public void setBatchSize(Long theBatchSize) {
|
||||
myBatchSize = theBatchSize;
|
||||
}
|
||||
|
||||
public List<String> getUrls() {
|
||||
if (myUrls == null) {
|
||||
myUrls = new ArrayList<>();
|
||||
}
|
||||
return myUrls;
|
||||
}
|
||||
|
||||
public void setUrls(List<String> theUrls) {
|
||||
myUrls = theUrls;
|
||||
}
|
||||
|
||||
public MdmSubmitEvent addUrl(String theUrl) {
|
||||
getUrls().add(theUrl);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isBatchJob() {
|
||||
return myIsBatchJob;
|
||||
}
|
||||
|
||||
public void setBatchJob(boolean theBatchJob) {
|
||||
myIsBatchJob = theBatchJob;
|
||||
}
|
||||
}
|
|
@ -21,13 +21,13 @@ package ca.uhn.fhir.mdm.provider;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageLinkBuilder;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageLinkTuple;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.TransactionLogMessages;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
|
|
@ -21,11 +21,16 @@ package ca.uhn.fhir.mdm.provider;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmHistorySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmHistoryEvent;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
|
@ -34,7 +39,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
public class MdmLinkHistoryProviderDstu3Plus extends BaseMdmProvider {
|
||||
|
@ -42,9 +49,15 @@ public class MdmLinkHistoryProviderDstu3Plus extends BaseMdmProvider {
|
|||
|
||||
private final IMdmControllerSvc myMdmControllerSvc;
|
||||
|
||||
public MdmLinkHistoryProviderDstu3Plus(FhirContext theFhirContext, IMdmControllerSvc theMdmControllerSvc) {
|
||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
public MdmLinkHistoryProviderDstu3Plus(
|
||||
FhirContext theFhirContext,
|
||||
IMdmControllerSvc theMdmControllerSvc,
|
||||
IInterceptorBroadcaster theIInterceptorBroadcaster) {
|
||||
super(theFhirContext);
|
||||
myMdmControllerSvc = theMdmControllerSvc;
|
||||
myInterceptorBroadcaster = theIInterceptorBroadcaster;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_LINK_HISTORY, idempotent = true)
|
||||
|
@ -79,6 +92,27 @@ public class MdmLinkHistoryProviderDstu3Plus extends BaseMdmProvider {
|
|||
|
||||
parametersFromMdmLinkRevisions(retVal, mdmLinkRevisionsFromSvc);
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_POST_LINK_HISTORY)) {
|
||||
// MDM_POST_LINK_HISTORY hook
|
||||
MdmHistoryEvent historyEvent = new MdmHistoryEvent();
|
||||
historyEvent.setMdmLinkRevisions(mdmLinkRevisionsFromSvc);
|
||||
if (isNotEmpty(theResourceIds)) {
|
||||
historyEvent.setSourceIds(theResourceIds.stream()
|
||||
.map(IPrimitiveType::getValueAsString)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
if (isNotEmpty(theMdmGoldenResourceIds)) {
|
||||
historyEvent.setGoldenResourceIds(theMdmGoldenResourceIds.stream()
|
||||
.map(IPrimitiveType::getValueAsString)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
HookParams params = new HookParams();
|
||||
params.add(RequestDetails.class, theRequestDetails);
|
||||
params.add(MdmHistoryEvent.class, historyEvent);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_LINK_HISTORY, params);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,21 @@ package ca.uhn.fhir.mdm.provider;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmQuerySearchParameters;
|
||||
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
|
||||
import ca.uhn.fhir.mdm.model.MdmCreateOrUpdateParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmMergeGoldenResourcesParams;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.model.MdmUnduplicateGoldenResourceParams;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmSubmitEvent;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
|
@ -57,16 +64,23 @@ import java.util.stream.Collectors;
|
|||
import javax.annotation.Nonnull;
|
||||
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_OFFSET;
|
||||
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
||||
private static final Logger ourLog = getLogger(MdmProviderDstu3Plus.class);
|
||||
|
||||
private static final String PATIENT_RESOURCE = "Patient";
|
||||
private static final String PRACTITIONER_RESOURCE = "Practitioner";
|
||||
|
||||
private final IMdmControllerSvc myMdmControllerSvc;
|
||||
private final IMdmSubmitSvc myMdmSubmitSvc;
|
||||
private final IMdmSettings myMdmSettings;
|
||||
private final MdmControllerHelper myMdmControllerHelper;
|
||||
|
||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
public static final int DEFAULT_PAGE_SIZE = 20;
|
||||
public static final int MAX_PAGE_SIZE = 100;
|
||||
|
||||
|
@ -81,14 +95,22 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IMdmControllerSvc theMdmControllerSvc,
|
||||
MdmControllerHelper theMdmHelper,
|
||||
IMdmSubmitSvc theMdmSubmitSvc,
|
||||
IInterceptorBroadcaster theIInterceptorBroadcaster,
|
||||
IMdmSettings theIMdmSettings) {
|
||||
super(theFhirContext);
|
||||
myMdmControllerSvc = theMdmControllerSvc;
|
||||
myMdmControllerHelper = theMdmHelper;
|
||||
myMdmSubmitSvc = theMdmSubmitSvc;
|
||||
myInterceptorBroadcaster = theIInterceptorBroadcaster;
|
||||
myMdmSettings = theIMdmSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for matches for the provided patient resource
|
||||
* @param thePatient - the patient resource
|
||||
* @param theRequestDetails - the request details
|
||||
* @return - any matches to the provided patient resource
|
||||
*/
|
||||
@Operation(name = ProviderConstants.EMPI_MATCH, typeName = "Patient")
|
||||
public IBaseBundle match(
|
||||
@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1, typeName = "Patient")
|
||||
|
@ -100,6 +122,14 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
return myMdmControllerHelper.getMatchesAndPossibleMatchesForResource(thePatient, "Patient", theRequestDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for matches for hte provided resource.
|
||||
*
|
||||
* @param theResource - the resource to match on
|
||||
* @param theResourceType - the resource type
|
||||
* @param theRequestDetails - the request details
|
||||
* @return - any matches to the provided resource
|
||||
*/
|
||||
@Operation(name = ProviderConstants.MDM_MATCH)
|
||||
public IBaseBundle serverMatch(
|
||||
@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) IAnyResource theResource,
|
||||
|
@ -138,11 +168,15 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
theRequestDetails,
|
||||
operationType,
|
||||
getResourceType(ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theFromGoldenResourceId));
|
||||
return myMdmControllerSvc.mergeGoldenResources(
|
||||
theFromGoldenResourceId.getValueAsString(),
|
||||
theToGoldenResourceId.getValueAsString(),
|
||||
theMergedResource,
|
||||
txContext);
|
||||
|
||||
MdmMergeGoldenResourcesParams params = new MdmMergeGoldenResourcesParams();
|
||||
params.setFromGoldenResourceId(theFromGoldenResourceId.getValueAsString());
|
||||
params.setToGoldenResourceId(theToGoldenResourceId.getValueAsString());
|
||||
params.setManuallyMergedResource(theMergedResource);
|
||||
params.setMdmTransactionContext(txContext);
|
||||
params.setRequestDetails(theRequestDetails);
|
||||
|
||||
return myMdmControllerSvc.mergeGoldenResources(params);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_UPDATE_LINK)
|
||||
|
@ -155,14 +189,18 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IPrimitiveType<String> theMatchResult,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
validateUpdateLinkParameters(theGoldenResourceId, theResourceId, theMatchResult);
|
||||
return myMdmControllerSvc.updateLink(
|
||||
theGoldenResourceId.getValueAsString(),
|
||||
theResourceId.getValue(),
|
||||
theMatchResult.getValue(),
|
||||
createMdmContext(
|
||||
|
||||
MdmCreateOrUpdateParams updateLinkParams = new MdmCreateOrUpdateParams();
|
||||
updateLinkParams.setGoldenResourceId(theGoldenResourceId.getValueAsString());
|
||||
updateLinkParams.setResourceId(theResourceId.getValue());
|
||||
updateLinkParams.setMatchResult(MdmControllerUtil.extractMatchResultOrNull(theMatchResult.getValue()));
|
||||
updateLinkParams.setMdmContext(createMdmContext(
|
||||
theRequestDetails,
|
||||
MdmTransactionContext.OperationType.UPDATE_LINK,
|
||||
getResourceType(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId)));
|
||||
updateLinkParams.setRequestDetails(theRequestDetails);
|
||||
|
||||
return myMdmControllerSvc.updateLink(updateLinkParams);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_CREATE_LINK)
|
||||
|
@ -175,14 +213,18 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IPrimitiveType<String> theMatchResult,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
validateCreateLinkParameters(theGoldenResourceId, theResourceId, theMatchResult);
|
||||
return myMdmControllerSvc.createLink(
|
||||
theGoldenResourceId.getValueAsString(),
|
||||
theResourceId.getValue(),
|
||||
extractStringOrNull(theMatchResult),
|
||||
createMdmContext(
|
||||
|
||||
MdmCreateOrUpdateParams params = new MdmCreateOrUpdateParams();
|
||||
params.setGoldenResourceId(theGoldenResourceId.getValueAsString());
|
||||
params.setResourceId(theResourceId.getValue());
|
||||
params.setMatchResult(MdmControllerUtil.extractMatchResultOrNull(extractStringOrNull(theMatchResult)));
|
||||
params.setRequestDetails(theRequestDetails);
|
||||
params.setMdmContext(createMdmContext(
|
||||
theRequestDetails,
|
||||
MdmTransactionContext.OperationType.CREATE_LINK,
|
||||
getResourceType(ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId)));
|
||||
|
||||
return myMdmControllerSvc.createLink(params);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
|
@ -203,7 +245,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
|
||||
List<String> resourceNames = new ArrayList<>();
|
||||
|
||||
if (theResourceNames != null) {
|
||||
if (isNotEmpty(theResourceNames)) {
|
||||
resourceNames.addAll(
|
||||
theResourceNames.stream().map(IPrimitiveType::getValue).collect(Collectors.toList()));
|
||||
validateResourceNames(resourceNames);
|
||||
|
@ -316,16 +358,19 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
@OperationParam(name = ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 1, max = 1, typeName = "string")
|
||||
IPrimitiveType<String> theResourceId,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
validateNotDuplicateParameters(theGoldenResourceId, theResourceId);
|
||||
myMdmControllerSvc.notDuplicateGoldenResource(
|
||||
theGoldenResourceId.getValue(),
|
||||
theResourceId.getValue(),
|
||||
createMdmContext(
|
||||
|
||||
MdmUnduplicateGoldenResourceParams params = new MdmUnduplicateGoldenResourceParams();
|
||||
params.setRequestDetails(theRequestDetails);
|
||||
params.setGoldenResourceId(theGoldenResourceId.getValueAsString());
|
||||
params.setTargetGoldenResourceId(theResourceId.getValueAsString());
|
||||
params.setMdmContext(createMdmContext(
|
||||
theRequestDetails,
|
||||
MdmTransactionContext.OperationType.NOT_DUPLICATE,
|
||||
getResourceType(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId)));
|
||||
|
||||
myMdmControllerSvc.unduplicateGoldenResource(params);
|
||||
|
||||
IBaseParameters retval = ParametersUtil.newInstance(myFhirContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myFhirContext, retval, "success", true);
|
||||
return retval;
|
||||
|
@ -348,24 +393,22 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
String criteria = convertStringTypeToString(theCriteria);
|
||||
String resourceType = convertStringTypeToString(theResourceType);
|
||||
long submittedCount;
|
||||
IBaseParameters retval;
|
||||
if (theRequestDetails.isPreferRespondAsync()) {
|
||||
List<String> urls = buildUrlsForJob(criteria, resourceType);
|
||||
return myMdmControllerSvc.submitMdmSubmitJob(urls, theBatchSize, theRequestDetails);
|
||||
retval = myMdmControllerSvc.submitMdmSubmitJob(urls, theBatchSize, theRequestDetails);
|
||||
} else {
|
||||
if (StringUtils.isNotBlank(resourceType)) {
|
||||
submittedCount =
|
||||
myMdmSubmitSvc.submitSourceResourceTypeToMdm(resourceType, criteria, theRequestDetails);
|
||||
} else {
|
||||
submittedCount = myMdmSubmitSvc.submitAllSourceTypesToMdm(criteria, theRequestDetails);
|
||||
}
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
submittedCount = synchronousMdmSubmit(resourceType, null, criteria, theRequestDetails);
|
||||
retval = buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private List<String> buildUrlsForJob(String criteria, String resourceType) {
|
||||
List<String> urls = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(resourceType)) {
|
||||
if (isNotBlank(resourceType)) {
|
||||
String theUrl = resourceType + "?" + criteria;
|
||||
urls.add(theUrl);
|
||||
} else {
|
||||
|
@ -388,7 +431,8 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
@OperationParam(name = ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, typeName = "integer")
|
||||
})
|
||||
public IBaseParameters mdmBatchPatientInstance(@IdParam IIdType theIdParam, RequestDetails theRequest) {
|
||||
long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam, theRequest);
|
||||
|
||||
long submittedCount = synchronousMdmSubmit(null, theIdParam, null, theRequest);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
|
@ -406,11 +450,11 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IPrimitiveType<BigDecimal> theBatchSize,
|
||||
ServletRequestDetails theRequest) {
|
||||
if (theRequest.isPreferRespondAsync()) {
|
||||
String theUrl = "Patient?";
|
||||
String theUrl = PATIENT_RESOURCE + "?";
|
||||
return myMdmControllerSvc.submitMdmSubmitJob(Collections.singletonList(theUrl), theBatchSize, theRequest);
|
||||
} else {
|
||||
String criteria = convertStringTypeToString(theCriteria);
|
||||
long submittedCount = myMdmSubmitSvc.submitPatientTypeToMdm(criteria, theRequest);
|
||||
long submittedCount = synchronousMdmSubmit(PATIENT_RESOURCE, null, criteria, theRequest);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +467,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
@OperationParam(name = ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, typeName = "integer")
|
||||
})
|
||||
public IBaseParameters mdmBatchPractitionerInstance(@IdParam IIdType theIdParam, RequestDetails theRequest) {
|
||||
long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam, theRequest);
|
||||
long submittedCount = synchronousMdmSubmit(null, theIdParam, null, theRequest);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
|
@ -441,11 +485,11 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IPrimitiveType<BigDecimal> theBatchSize,
|
||||
ServletRequestDetails theRequest) {
|
||||
if (theRequest.isPreferRespondAsync()) {
|
||||
String theUrl = "Practitioner?";
|
||||
String theUrl = PRACTITIONER_RESOURCE + "?";
|
||||
return myMdmControllerSvc.submitMdmSubmitJob(Collections.singletonList(theUrl), theBatchSize, theRequest);
|
||||
} else {
|
||||
String criteria = convertStringTypeToString(theCriteria);
|
||||
long submittedCount = myMdmSubmitSvc.submitPractitionerTypeToMdm(criteria, theRequest);
|
||||
long submittedCount = synchronousMdmSubmit(PRACTITIONER_RESOURCE, null, criteria, theRequest);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
}
|
||||
|
@ -482,4 +526,58 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
|
|||
IIdType idType = MdmControllerUtil.getGoldenIdDtOrThrowException(theParamName, theResourceId);
|
||||
return idType.getResourceType();
|
||||
}
|
||||
|
||||
private long synchronousMdmSubmit(
|
||||
String theResourceType, IIdType theIdType, String theCriteria, RequestDetails theRequestDetails) {
|
||||
long submittedCount = -1;
|
||||
List<String> urls = new ArrayList<>();
|
||||
if (theIdType != null) {
|
||||
submittedCount = mdmSubmitWithId(theIdType, theRequestDetails, urls);
|
||||
} else if (isNotBlank(theResourceType)) {
|
||||
submittedCount = submitResourceTypeWithCriteria(theResourceType, theCriteria, theRequestDetails, urls);
|
||||
} else {
|
||||
submittedCount = submitAll(theCriteria, theRequestDetails, urls);
|
||||
}
|
||||
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_SUBMIT)) {
|
||||
// MDM_SUBMIT synchronous submit
|
||||
MdmSubmitEvent submitEvent = new MdmSubmitEvent();
|
||||
submitEvent.setBatchJob(false);
|
||||
submitEvent.setUrls(urls);
|
||||
|
||||
HookParams hookParams = new HookParams();
|
||||
hookParams.add(RequestDetails.class, theRequestDetails);
|
||||
hookParams.add(MdmSubmitEvent.class, submitEvent);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.MDM_SUBMIT, hookParams);
|
||||
}
|
||||
|
||||
return submittedCount;
|
||||
}
|
||||
|
||||
private long mdmSubmitWithId(IIdType theIdType, RequestDetails theRequestDetails, List<String> theUrls) {
|
||||
theUrls.add(theIdType.getValue());
|
||||
return myMdmSubmitSvc.submitSourceResourceToMdm(theIdType, theRequestDetails);
|
||||
}
|
||||
|
||||
private long submitResourceTypeWithCriteria(
|
||||
String theResourceType, String theCriteria, RequestDetails theRequestDetails, List<String> theUrls) {
|
||||
String url = theResourceType;
|
||||
if (isNotEmpty(theCriteria)) {
|
||||
url += "?" + theCriteria;
|
||||
}
|
||||
theUrls.add(url);
|
||||
|
||||
return myMdmSubmitSvc.submitSourceResourceTypeToMdm(theResourceType, theCriteria, theRequestDetails);
|
||||
}
|
||||
|
||||
private long submitAll(String theCriteria, RequestDetails theRequestDetails, List<String> theUrls) {
|
||||
// submitAllSourceTypes only runs through
|
||||
// valid MDM source types
|
||||
List<String> resourceTypes = myMdmSettings.getMdmRules().getMdmTypes();
|
||||
for (String resourceType : resourceTypes) {
|
||||
String url = resourceType + (isNotEmpty(theCriteria) ? "?" + theCriteria : "");
|
||||
theUrls.add(url);
|
||||
}
|
||||
return myMdmSubmitSvc.submitAllSourceTypesToMdm(theCriteria, theRequestDetails);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.mdm.provider;
|
|||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
|
@ -55,19 +56,28 @@ public class MdmProviderLoader {
|
|||
@Autowired
|
||||
private JpaStorageSettings myStorageSettings;
|
||||
|
||||
private MdmProviderDstu3Plus myMdmProvider;
|
||||
@Autowired
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
private BaseMdmProvider myMdmProvider;
|
||||
private MdmLinkHistoryProviderDstu3Plus myMdmHistoryProvider;
|
||||
|
||||
public void loadProvider() {
|
||||
switch (myFhirContext.getVersion().getVersion()) {
|
||||
case DSTU3:
|
||||
case R4:
|
||||
myMdmProvider = new MdmProviderDstu3Plus(
|
||||
myFhirContext, myMdmControllerSvc, myMdmControllerHelper, myMdmSubmitSvc, myMdmSettings);
|
||||
myResourceProviderFactory.addSupplier(() -> myMdmProvider);
|
||||
myResourceProviderFactory.addSupplier(() -> new MdmProviderDstu3Plus(
|
||||
myFhirContext,
|
||||
myMdmControllerSvc,
|
||||
myMdmControllerHelper,
|
||||
myMdmSubmitSvc,
|
||||
myInterceptorBroadcaster,
|
||||
myMdmSettings));
|
||||
if (myStorageSettings.isNonResourceDbHistoryEnabled()) {
|
||||
myMdmHistoryProvider = new MdmLinkHistoryProviderDstu3Plus(myFhirContext, myMdmControllerSvc);
|
||||
myResourceProviderFactory.addSupplier(() -> myMdmHistoryProvider);
|
||||
myResourceProviderFactory.addSupplier(() -> {
|
||||
return new MdmLinkHistoryProviderDstu3Plus(
|
||||
myFhirContext, myMdmControllerSvc, myInterceptorBroadcaster);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
@ -21,7 +21,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-caching-api</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.9.1-SNAPSHOT</version>
|
||||
<version>6.9.2-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue