Address review comments

This commit is contained in:
Tadgh 2020-07-22 11:58:08 -07:00
parent 249f5e5947
commit bbe6d5600e
23 changed files with 195 additions and 219 deletions

View File

@ -20,3 +20,4 @@
The method `FhirContext#getResourceNames()` has been renamed to `FhirContext#getResourceTypes()`. HAPI currently
goes back and forth between the two, but is consolidating on `Types`.
"

View File

@ -89,7 +89,7 @@ public class EmpiLink {
private Date myUpdated;
@Column(name = "VERSION", nullable = false, length = VERSION_LENGTH)
private String myVersion;
private java.lang.String myVersion;
/** This link was created as a result of an eid match **/
@Column(name = "EID_MATCH")
@ -107,12 +107,12 @@ public class EmpiLink {
public EmpiLink() {}
public EmpiLink(String theVersion) {
public EmpiLink(java.lang.String theVersion) {
myVersion = theVersion;
}
@Column(name = "TARGET_TYPE", nullable = true)
private EmpiTargetType myEmpiTargetType;
@Column(name = "TARGET_TYPE", nullable = true, length = 40)
private String myEmpiTargetType;
public Long getId() {
return myId;
@ -221,11 +221,11 @@ public class EmpiLink {
return this;
}
public String getVersion() {
public java.lang.String getVersion() {
return myVersion;
}
public EmpiLink setVersion(String theVersion) {
public EmpiLink setVersion(java.lang.String theVersion) {
myVersion = theVersion;
return this;
}
@ -275,7 +275,7 @@ public class EmpiLink {
}
@Override
public String toString() {
public java.lang.String toString() {
return new ToStringBuilder(this)
.append("myPersonPid", myPersonPid)
.append("myTargetPid", myTargetPid)
@ -288,11 +288,11 @@ public class EmpiLink {
.toString();
}
public EmpiTargetType getEmpiTargetType() {
public String getEmpiTargetType() {
return myEmpiTargetType;
}
public void setEmpiTargetType(EmpiTargetType theEmpiTargetType) {
public void setEmpiTargetType(String theEmpiTargetType) {
myEmpiTargetType = theEmpiTargetType;
}
}

View File

@ -1,22 +0,0 @@
package ca.uhn.fhir.jpa.entity;
/**
* Possible legal Empi Target Types, stored in database as ordinals.
*/
public enum EmpiTargetType {
/**
*
* ORDER MATTERS, IF ADDING NEW VALUES, APPEND ONLY.
*/
PATIENT,
PRACTITIONER,
PERSON;
EmpiTargetType(){}
public static EmpiTargetType valueOfCaseInsensitive(String theValue) {
return valueOf(EmpiTargetType.class, theValue.toUpperCase());
}
}

View File

@ -22,13 +22,13 @@ package ca.uhn.fhir.jpa.empi.config;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkQuerySvc;
import ca.uhn.fhir.empi.api.IEmpiLinkSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkUpdaterSvc;
import ca.uhn.fhir.empi.api.IEmpiMatchFinderSvc;
import ca.uhn.fhir.empi.api.IEmpiPersonMergerSvc;
import ca.uhn.fhir.empi.api.IEmpiQueueSubmitterSvc;
import ca.uhn.fhir.empi.api.IEmpiChannelSubmitterSvc;
import ca.uhn.fhir.empi.api.IEmpiSettings;
import ca.uhn.fhir.empi.log.Logs;
import ca.uhn.fhir.empi.provider.EmpiProviderLoader;
@ -45,14 +45,14 @@ import ca.uhn.fhir.jpa.empi.interceptor.EmpiStorageInterceptor;
import ca.uhn.fhir.jpa.empi.interceptor.IEmpiStorageInterceptor;
import ca.uhn.fhir.jpa.empi.svc.EmpiBatchSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiEidUpdateService;
import ca.uhn.fhir.jpa.empi.svc.EmpiExpungeSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiResetSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiLinkQuerySvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiLinkSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiLinkUpdaterSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiMatchFinderSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiMatchLinkSvc;
import ca.uhn.fhir.jpa.empi.svc.EmpiPersonMergerSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiQueueSubmitterSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiChannelSubmitterSvcImpl;
import ca.uhn.fhir.jpa.empi.svc.EmpiResourceDaoSvc;
import ca.uhn.fhir.jpa.empi.svc.candidate.EmpiCandidateSearchCriteriaBuilderSvc;
import ca.uhn.fhir.jpa.empi.svc.candidate.EmpiCandidateSearchSvc;
@ -60,10 +60,13 @@ import ca.uhn.fhir.jpa.empi.svc.candidate.EmpiPersonFindingSvc;
import ca.uhn.fhir.jpa.empi.svc.candidate.FindCandidateByEidSvc;
import ca.uhn.fhir.jpa.empi.svc.candidate.FindCandidateByLinkSvc;
import ca.uhn.fhir.jpa.empi.svc.candidate.FindCandidateByScoreSvc;
import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
import ca.uhn.fhir.rest.server.util.ISearchParamRetriever;
import org.slf4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Configuration
public class EmpiConsumerConfig {
@ -95,8 +98,9 @@ public class EmpiConsumerConfig {
}
@Bean
IEmpiQueueSubmitterSvc empiQueueSubmitterSvc() {
return new EmpiQueueSubmitterSvcImpl();
@Lazy
IEmpiChannelSubmitterSvc empiQueueSubmitterSvc(IChannelNamer theChannelNamer, FhirContext theFhirContext, IChannelFactory theChannelFactory) {
return new EmpiChannelSubmitterSvcImpl(theChannelNamer, theFhirContext, theChannelFactory);
}
@Bean
@ -176,8 +180,8 @@ public class EmpiConsumerConfig {
}
@Bean
IEmpiExpungeSvc empiExpungeSvc() {
return new EmpiExpungeSvcImpl();
IEmpiResetSvc empiExpungeSvc() {
return new EmpiResetSvcImpl();
}
@Bean

View File

@ -29,7 +29,6 @@ import ca.uhn.fhir.empi.model.EmpiTransactionContext;
import ca.uhn.fhir.jpa.dao.data.IEmpiLinkDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.entity.EmpiLink;
import ca.uhn.fhir.jpa.entity.EmpiTargetType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
@ -69,7 +68,7 @@ public class EmpiLinkDaoSvc {
// Preserve these flags for link updates
empiLink.setEidMatch(theMatchOutcome.isEidMatch() | empiLink.isEidMatch());
empiLink.setNewPerson(theMatchOutcome.isNewPerson() | empiLink.isNewPerson());
empiLink.setEmpiTargetType(determineTargetType(theTarget));
empiLink.setEmpiTargetType(myFhirContext.getResourceType(theTarget));
if (empiLink.getScore() != null) {
empiLink.setScore(Math.max(theMatchOutcome.score, empiLink.getScore()));
} else {
@ -83,12 +82,6 @@ public class EmpiLinkDaoSvc {
return empiLink;
}
private EmpiTargetType determineTargetType(IBaseResource theTarget) {
String resourceType = myFhirContext.getResourceType(theTarget);
return EmpiTargetType.valueOfCaseInsensitive(resourceType);
}
@Nonnull
public EmpiLink getOrCreateEmpiLinkByPersonPidAndTargetPid(Long thePersonPid, Long theResourcePid) {
Optional<EmpiLink> oExisting = getLinkByPersonPidAndTargetPid(thePersonPid, theResourcePid);
@ -115,7 +108,7 @@ public class EmpiLinkDaoSvc {
}
/**
* Given a Target Pid, and a match result, return all links which match these criteria.
* Given a Target Pid, and a match result, return all links that match these criteria.
*
* @param theTargetPid the target of the relationship.
* @param theMatchResult the Match Result of the relationship
@ -250,14 +243,14 @@ public class EmpiLinkDaoSvc {
}
/**
* Given a valid {@link EmpiTargetType}, delete all {@link EmpiLink} entities for that type, and get the Pids
* Given a valid {@link String}, delete all {@link EmpiLink} entities for that type, and get the Pids
* for the Person resources which were the sources of the links.
*
* @param theTargetType the type of relationship you would like to delete.
*
* @return A list of longs representing the Pids of the Person resources used as the sources of the relationships that were deleted.
*/
public List<Long> deleteAllEmpiLinksOfTypeAndReturnPersonPids(EmpiTargetType theTargetType) {
public List<Long> deleteAllEmpiLinksOfTypeAndReturnPersonPids(String theTargetType) {
EmpiLink link = new EmpiLink();
link.setEmpiTargetType(theTargetType);
Example<EmpiLink> exampleLink = Example.of(link);
@ -274,7 +267,7 @@ public class EmpiLinkDaoSvc {
*
* @return A list of longs, each representing the source person of an {@link EmpiLink} that was deleted.
*/
public List<Long> deleteEmpiLinksAndReturnPersonPidsForTypeAndTarget(EmpiTargetType theTargetType, IIdType theId) {
public List<Long> deleteEmpiLinksAndReturnPersonPidsForTypeAndTarget(String theTargetType, IIdType theId) {
EmpiLink link = new EmpiLink();
link.setEmpiTargetType(theTargetType);
link.setTargetPid(myIdHelperService.getPidOrThrowException(theId));

View File

@ -1,7 +1,8 @@
package ca.uhn.fhir.jpa.empi.svc;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiQueueSubmitterSvc;
import ca.uhn.fhir.empi.api.IEmpiChannelSubmitterSvc;
import ca.uhn.fhir.empi.util.EmpiUtil;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
@ -14,7 +15,6 @@ import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Patient;
@ -24,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@ -36,16 +37,16 @@ public class EmpiBatchSvcImpl implements IEmpiBatchService {
private EmpiSearchParamSvc myEmpiSearchParamSvc;
@Autowired
private IEmpiQueueSubmitterSvc myEmpiQueueSubmitterSvc;
private IEmpiChannelSubmitterSvc myEmpiQueueSubmitterSvc;
@Autowired
private SearchBuilderFactory mySearchBuilderFactory;
private static final int QUEUE_ADDING_PAGE_SIZE = 100;
private static final int BUFFER_SIZE = 100;
@Override
@Transactional
public int runEmpiOnAllTargetTypes(String theCriteria) {
public long runEmpiOnAllTargetTypes(String theCriteria) {
int submittedCount = 0;
submittedCount += runEmpiOnPatientType(theCriteria);
submittedCount += runEmpiOnPractitionerType(theCriteria);
@ -54,86 +55,86 @@ public class EmpiBatchSvcImpl implements IEmpiBatchService {
@Override
@Transactional
public int runEmpiOnTargetType(String theTargetType, String theCriteria) {
public long runEmpiOnTargetType(String theTargetType, String theCriteria) {
resolveTargetTypeOrThrowException(theTargetType);
SearchParameterMap spMap = getSearchParameterMapFromCriteria(theTargetType, theCriteria);
spMap.setLoadSynchronousUpTo(QUEUE_ADDING_PAGE_SIZE);
int total = 0;
ISearchBuilder mySearchBuilder = mySearchBuilderFactory.newSearchBuilder(myDaoRegistry.getResourceDao(theTargetType), theTargetType, Patient.class);
SearchParameterMap spMap = myEmpiSearchParamSvc.getSearchParameterMapFromCriteria(theTargetType, theCriteria);
spMap.setLoadSynchronousUpTo(BUFFER_SIZE);
ISearchBuilder searchBuilder = mySearchBuilderFactory.newSearchBuilder(myDaoRegistry.getResourceDao(theTargetType), theTargetType, Patient.class);
return submitAllMatchingResourcesToEmpiChannel(spMap, searchBuilder);
}
private long submitAllMatchingResourcesToEmpiChannel(SearchParameterMap theSpMap, ISearchBuilder theSearchBuilder) {
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(null, UUID.randomUUID().toString());
try (IResultIterator query = mySearchBuilder.createQuery(spMap, searchRuntimeDetails, null, RequestPartitionId.defaultPartition())) {
Collection<ResourcePersistentId> pidsToSubmit = new ArrayList<>();
List<IBaseResource> resourceToBeSubmitted = new ArrayList<>();
while (query.hasNext()) {
pidsToSubmit.add(query.next());
if (pidsToSubmit.size() == QUEUE_ADDING_PAGE_SIZE || !query.hasNext()) {
total = loadResourcesAndSubmitToEmpi(total, mySearchBuilder, pidsToSubmit, resourceToBeSubmitted);
resourceToBeSubmitted.clear();
}
}
long total = 0;
try (IResultIterator query = theSearchBuilder.createQuery(theSpMap, searchRuntimeDetails, null, RequestPartitionId.defaultPartition())) {
Collection<ResourcePersistentId> pidBatch;
do {
pidBatch = getPidBatch(query);
total += loadPidsAndSubmitToEmpiChannel(theSearchBuilder, pidBatch);
} while (query.hasNext());
} catch (IOException theE) {
throw new InternalErrorException("Failure while attempting to query resources for " + ProviderConstants.OPERATION_EMPI_BATCH_RUN, theE);
}
return total;
}
private int loadResourcesAndSubmitToEmpi(int theTotal, ISearchBuilder theMySearchBuilder, Collection<ResourcePersistentId> thePidsToSubmit, List<IBaseResource> theResourceToBeSubmitted) {
//TODO GGG ask ken how this works. specifically includePids?
theMySearchBuilder.loadResourcesByPid(thePidsToSubmit, thePidsToSubmit, theResourceToBeSubmitted, false, null);
theResourceToBeSubmitted
.forEach(resource -> myEmpiQueueSubmitterSvc.manuallySubmitResourceToEmpi(resource));
theTotal += theResourceToBeSubmitted.size();
return theTotal;
/**
* Given an iterator, get a batch of max size BUFFER_SIZE.
*
* @param theQuery the iterator.
*
* @return a collection of ResourcePersistentId entities.
*/
public Collection<ResourcePersistentId> getPidBatch(IResultIterator theQuery) {
Collection<ResourcePersistentId> batch = new ArrayList<>();
while (theQuery.hasNext() && batch.size() <= BUFFER_SIZE) {
batch.add(theQuery.next());
}
return batch;
}
/**
* Given a collection of ResourcePersistentId objects, and a search builder, load the IBaseResources and submit them to
* the EMPI channel for processing.
*
* @param theSearchBuilder the related DAO search builder.
* @param thePidsToSubmit The collection of PIDs whos resources you want to submit for EMPI processing.
*
* @return The total count of submitted resources.
*/
private long loadPidsAndSubmitToEmpiChannel(ISearchBuilder theSearchBuilder, Collection<ResourcePersistentId> thePidsToSubmit) {
List<IBaseResource> resourcesToSubmit = new ArrayList<>();
theSearchBuilder.loadResourcesByPid(thePidsToSubmit, Collections.emptyList(), resourcesToSubmit, false, null);
resourcesToSubmit
.forEach(resource -> myEmpiQueueSubmitterSvc.submitResourceToEmpiChannel(resource));
return resourcesToSubmit.size();
}
@Override
@Transactional
public int runEmpiOnPractitionerType(String theCriteria) {
public long runEmpiOnPractitionerType(String theCriteria) {
return runEmpiOnTargetType("Practitioner", theCriteria);
}
@Override
@Transactional
public int runEmpiOnPatientType(String theCriteria) {
public long runEmpiOnPatientType(String theCriteria) {
return runEmpiOnTargetType("Patient", theCriteria);
}
@Override
@Transactional
public int runEmpiOnTarget(IIdType theId, String theTargetType) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theTargetType);
public long runEmpiOnTarget(IIdType theId) {
resolveTargetTypeOrThrowException(theId.getResourceType());
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theId.getResourceType());
IBaseResource read = resourceDao.read(theId);
myEmpiQueueSubmitterSvc.manuallySubmitResourceToEmpi(read);
myEmpiQueueSubmitterSvc.submitResourceToEmpiChannel(read);
return 1;
}
@Override
@Transactional
public int runEmpiOnTargetPractitioner(IIdType theId) {
return runEmpiOnTarget(theId, "Practitioner");
}
@Override
@Transactional
public int runEmpiOnTargetPatient(IIdType theId) {
return runEmpiOnTarget(theId, "Patient");
}
private SearchParameterMap getSearchParameterMapFromCriteria(String theTargetType, String theCriteria) {
SearchParameterMap spMap;
if (!StringUtils.isBlank(theCriteria)) {
spMap = myEmpiSearchParamSvc.mapFromCriteria(theTargetType, theCriteria);
} else {
spMap = new SearchParameterMap();
}
return spMap;
}
private void resolveTargetTypeOrThrowException(String theResourceType) {
if (!theResourceType.equalsIgnoreCase("Patient") && !theResourceType.equalsIgnoreCase("Practitioner")) {
if (!EmpiUtil.supportedTargetType(theResourceType)) {
throw new InvalidRequestException(ProviderConstants.OPERATION_EMPI_BATCH_RUN + " does not support resource type: " + theResourceType);
}
}

View File

@ -1,7 +1,7 @@
package ca.uhn.fhir.jpa.empi.svc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.empi.api.IEmpiQueueSubmitterSvc;
import ca.uhn.fhir.empi.api.IEmpiChannelSubmitterSvc;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
@ -12,38 +12,46 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessageChannel;
import javax.annotation.PostConstruct;
import static ca.uhn.fhir.empi.api.IEmpiSettings.EMPI_CHANNEL_NAME;
/**
* This class is responsible for manual submissions of {@link IAnyResource} resources onto the Empi Queue.
*/
public class EmpiQueueSubmitterSvcImpl implements IEmpiQueueSubmitterSvc {
@Autowired
public class EmpiChannelSubmitterSvcImpl implements IEmpiChannelSubmitterSvc {
private IChannelNamer myChannelNamer;
private MessageChannel myEmpiChannelProducer;
@Autowired
private FhirContext myFhirContext;
@Autowired
private IChannelFactory myChannelFactory;
@Override
public void manuallySubmitResourceToEmpi(IBaseResource theResource) {
public void submitResourceToEmpiChannel(IBaseResource theResource) {
ResourceModifiedJsonMessage resourceModifiedJsonMessage = new ResourceModifiedJsonMessage();
ResourceModifiedMessage resourceModifiedMessage = new ResourceModifiedMessage(myFhirContext, theResource, ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED);
resourceModifiedMessage.setOperationType(ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED);
resourceModifiedJsonMessage.setPayload(resourceModifiedMessage);
myEmpiChannelProducer.send(resourceModifiedJsonMessage);
getEmpiChannelProducer().send(resourceModifiedJsonMessage);
}
@Autowired
public EmpiChannelSubmitterSvcImpl(IChannelNamer theChannelNamer, FhirContext theFhirContext, IChannelFactory theIChannelFactory) {
myChannelNamer = theChannelNamer;
myFhirContext = theFhirContext;
myChannelFactory = theIChannelFactory;
}
@PostConstruct
private void init() {
ChannelProducerSettings channelSettings = new ChannelProducerSettings();
String channelName = myChannelNamer.getChannelName(EMPI_CHANNEL_NAME, channelSettings);
myEmpiChannelProducer= myChannelFactory.getOrCreateProducer(channelName, ResourceModifiedJsonMessage.class, channelSettings);
}
private MessageChannel getEmpiChannelProducer() {
if (myEmpiChannelProducer == null) {
init();
}
return myEmpiChannelProducer;
}
}

View File

@ -20,10 +20,10 @@ package ca.uhn.fhir.jpa.empi.svc;
* #L%
*/
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.empi.util.EmpiUtil;
import ca.uhn.fhir.jpa.dao.expunge.IResourceExpungeService;
import ca.uhn.fhir.jpa.empi.dao.EmpiLinkDaoSvc;
import ca.uhn.fhir.jpa.entity.EmpiTargetType;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.slf4j.Logger;
@ -37,8 +37,8 @@ import java.util.concurrent.atomic.AtomicInteger;
* This class is in charge of Clearing out existing EMPI links, as well as deleting all persons related to those EMPI Links.
*
*/
public class EmpiExpungeSvcImpl implements IEmpiExpungeSvc {
private static final Logger ourLog = LoggerFactory.getLogger(EmpiExpungeSvcImpl.class);
public class EmpiResetSvcImpl implements IEmpiResetSvc {
private static final Logger ourLog = LoggerFactory.getLogger(EmpiResetSvcImpl.class);
@Autowired
EmpiLinkDaoSvc myEmpiLinkDaoSvc;
@ -48,24 +48,23 @@ public class EmpiExpungeSvcImpl implements IEmpiExpungeSvc {
@Override
public void expungeEmpiLinks(String theResourceType) {
EmpiTargetType targetType = getTargetTypeOrThrowException(theResourceType);
List<Long> longs = myEmpiLinkDaoSvc.deleteAllEmpiLinksOfTypeAndReturnPersonPids(targetType);
public void expungeAllEmpiLinksOfTargetType(String theResourceType) {
throwExceptionIfInvalidTargetType(theResourceType);
List<Long> longs = myEmpiLinkDaoSvc.deleteAllEmpiLinksOfTypeAndReturnPersonPids(theResourceType);
myResourceExpungeService.expungeCurrentVersionOfResources(null, longs, new AtomicInteger(longs.size()));
}
private EmpiTargetType getTargetTypeOrThrowException(String theResourceType) {
if (theResourceType.equalsIgnoreCase("Patient")) {
return EmpiTargetType.PATIENT;
} else if(theResourceType.equalsIgnoreCase("Practitioner")) {
return EmpiTargetType.PRACTITIONER;
} else {
private void throwExceptionIfInvalidTargetType(String theResourceType) {
if (!EmpiUtil.supportedTargetType(theResourceType)) {
throw new InvalidRequestException(ProviderConstants.EMPI_CLEAR + " does not support resource type: " + theResourceType);
}
}
/**
* TODO GGG this operation likely won't scale very well. Consider adding slicing
*/
@Override
public void expungeEmpiLinks() {
public void expungeAllEmpiLinks() {
List<Long> longs = myEmpiLinkDaoSvc.deleteAllEmpiLinksAndReturnPersonPids();
myResourceExpungeService.expungeCurrentVersionOfResources(null, longs, new AtomicInteger(longs.size()));
}

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.rest.server.util.ISearchParamRetriever;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -60,4 +61,23 @@ public class EmpiSearchParamSvc implements ISearchParamRetriever {
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
return mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
}
/**
* Given a target type, and a criteria string of the shape name=x&birthDate=y, generate a {@link SearchParameterMap}
* that represents this query.
*
* @param theTargetType the resource type to execute the search on
* @param theCriteria the string search criteria.
*
* @return the generated SearchParameterMap, or an empty one if there is no criteria.
*/
public SearchParameterMap getSearchParameterMapFromCriteria(String theTargetType, String theCriteria) {
SearchParameterMap spMap;
if (!StringUtils.isBlank(theCriteria)) {
spMap = mapFromCriteria(theTargetType, theCriteria);
} else {
spMap = new SearchParameterMap();
}
return spMap;
}
}

View File

@ -1,7 +1,7 @@
package ca.uhn.fhir.jpa.empi.provider;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkQuerySvc;
import ca.uhn.fhir.empi.api.IEmpiLinkUpdaterSvc;
import ca.uhn.fhir.empi.api.IEmpiMatchFinderSvc;
@ -25,7 +25,7 @@ public abstract class BaseProviderR4Test extends BaseEmpiR4Test {
@Autowired
private IResourceLoader myResourceLoader;
@Autowired
private IEmpiExpungeSvc myEmpiExpungeSvc;
private IEmpiResetSvc myEmpiExpungeSvc;
@Autowired
private IEmpiBatchService myEmpiBatchSvc;

View File

@ -49,7 +49,6 @@ public class EmpiProviderBatchR4Test extends BaseLinkR4Test {
@Test
public void testBatchRunOnAllPractitioners() {
assertLinkCount(2);
StringType criteria = null;
myEmpiProviderR4.clearEmpiLinks(null);
@ -58,7 +57,6 @@ public class EmpiProviderBatchR4Test extends BaseLinkR4Test {
}
@Test
public void testBatchRunOnSpecificPractitioner() {
assertLinkCount(2);
myEmpiProviderR4.clearEmpiLinks(null);
afterEmpiLatch.runWithExpectedCount(1, () -> myEmpiProviderR4.empiBatchPractitionerInstance(myPractitioner.getIdElement(), null));
assertLinkCount(1);
@ -66,7 +64,6 @@ public class EmpiProviderBatchR4Test extends BaseLinkR4Test {
@Test
public void testBatchRunOnNonExistentSpecificPractitioner() {
assertLinkCount(2);
myEmpiProviderR4.clearEmpiLinks(null);
try {
myEmpiProviderR4.empiBatchPractitionerInstance(new IdType("Practitioner/999"), null);

View File

@ -60,7 +60,6 @@ public class EmpiProviderClearLinkR4Test extends BaseLinkR4Test {
@Test
public void testClearPatientLinks() {
assertLinkCount(2);
Person read = myPersonDao.read(new IdDt(myPersonId.getValueAsString()).toVersionless());
assertThat(read, is(notNullValue()));
myEmpiProviderR4.clearEmpiLinks(new StringType("patient"));
@ -75,6 +74,8 @@ public class EmpiProviderClearLinkR4Test extends BaseLinkR4Test {
@Test
public void testClearPractitionerLinks() {
assertLinkCount(2);
Person read = myPersonDao.read(new IdDt(myPractitionerPersonId.getValueAsString()).toVersionless());
assertThat(read, is(notNullValue()));
myEmpiProviderR4.clearEmpiLinks(new StringType("practitioner"));
assertNoPractitionerLinksExist();
try {

View File

@ -46,12 +46,10 @@ class EmpiBatchSvcImplTest extends BaseEmpiR4Test {
}
assertLinkCount(0);
afterEmpiLatch.setExpectedCount(20);
//SUT
myEmpiBatchSvc.runEmpiOnAllTargetTypes(null);
afterEmpiLatch.runWithExpectedCount(20, () -> myEmpiBatchSvc.runEmpiOnAllTargetTypes(null));
afterEmpiLatch.awaitExpected();
assertLinkCount(20);
}
@ -63,12 +61,10 @@ class EmpiBatchSvcImplTest extends BaseEmpiR4Test {
}
assertLinkCount(0);
afterEmpiLatch.setExpectedCount(10);
//SUT
myEmpiBatchSvc.runEmpiOnTargetType("Patient", null);
afterEmpiLatch.runWithExpectedCount(10, () -> myEmpiBatchSvc.runEmpiOnTargetType("Patient", null));
afterEmpiLatch.awaitExpected();
assertLinkCount(10);
}
@ -80,12 +76,10 @@ class EmpiBatchSvcImplTest extends BaseEmpiR4Test {
}
assertLinkCount(0);
afterEmpiLatch.setExpectedCount(10);
//SUT
myEmpiBatchSvc.runEmpiOnAllTargetTypes(null);
afterEmpiLatch.runWithExpectedCount(10, () -> myEmpiBatchSvc.runEmpiOnAllTargetTypes(null));
afterEmpiLatch.awaitExpected();
assertLinkCount(10);
}
@ -95,11 +89,10 @@ class EmpiBatchSvcImplTest extends BaseEmpiR4Test {
createPatient(buildPatientWithNameIdAndBirthday("john", "john_id", DateUtils.addDays(new Date(), -300)));
assertLinkCount(0);
afterEmpiLatch.setExpectedCount(1);
myEmpiBatchSvc.runEmpiOnAllTargetTypes("Patient?name=gary");
//SUT
afterEmpiLatch.runWithExpectedCount(1, () -> myEmpiBatchSvc.runEmpiOnAllTargetTypes("Patient?name=gary"));
afterEmpiLatch.awaitExpected();
assertLinkCount(1);
}
}

View File

@ -102,7 +102,6 @@ public class AddForeignKeyTask extends BaseTableColumnTask {
throw e;
}
}
}
@Override

View File

@ -6,64 +6,46 @@ public interface IEmpiBatchService {
/**
* Submit all eligible resources for EMPI processing.
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI. NOTE:
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing.
* NOTE:
* When using this function, the criteria supplied must be valid for all EMPI types. e.g. , if you
* run this with the criteria birthDate=1990-06-28, it will fail, as Practitioner's do not have a birthday.
* run this with the criteria birthDate=1990-06-28, it will fail, as Practitioners do not have a birthday.
* Use with caution.
*
* @return
*/
int runEmpiOnAllTargetTypes(String theCriteria);
long runEmpiOnAllTargetTypes(String theCriteria);
/**
* Given a type and a search criteria, submit all found resources for EMPI processing.
*
* @param theTargetType the resource type that you wish to execute a search over for submission to EMPI.
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI.
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing..
* @return the number of resources submitted for EMPI processing.
*/
int runEmpiOnTargetType(String theTargetType, String theCriteria);
long runEmpiOnTargetType(String theTargetType, String theCriteria);
/**
* Convenience method which calls {@link #runEmpiOnTargetType(String, String)} with the type pre-populated.
* Convenience method that calls {@link #runEmpiOnTargetType(String, String)} with the type pre-populated.
*
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI.
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing.
* @return the number of resources submitted for EMPI processing.
*/
int runEmpiOnPractitionerType(String theCriteria);
long runEmpiOnPractitionerType(String theCriteria);
/**
* Convenience method which calls {@link #runEmpiOnTargetType(String, String)} with the type pre-populated.
* Convenience method that calls {@link #runEmpiOnTargetType(String, String)} with the type pre-populated.
*
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI.
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing.
* @return the number of resources submitted for EMPI processing.
*/
int runEmpiOnPatientType(String theCriteria);
long runEmpiOnPatientType(String theCriteria);
/**
* Given an ID and a target type valid for EMPI, manually submit the given ID for EMPI processing.
* @param theId the ID of the resource to process for EMPI.
* @param theTargetType The type of this resource.
* @return the constant `1`, as if this function returns successfully, it will have processed one resource for EMPI.
*/
int runEmpiOnTarget(IIdType theId, String theTargetType);
/**
* Convenience method which calls {@link #runEmpiOnTarget(IIdType, String)} with the type pre-populated
*
* @param theId the ID of the resource to run EMPI on.
*
* @return the constant 1, as this will perform one EMPI submission.
*/
int runEmpiOnTargetPractitioner(IIdType theId);
/**
* Convenience method which calls {@link #runEmpiOnTarget(IIdType, String)} with the type pre-populated
*
* @param theId the ID of the resource to run EMPI on.
*
* @return the constant 1, as this will perform one EMPI submission.
*/
int runEmpiOnTargetPatient(IIdType theId);
long runEmpiOnTarget(IIdType theId);
}

View File

@ -0,0 +1,12 @@
package ca.uhn.fhir.empi.api;
import org.hl7.fhir.instance.model.api.IBaseResource;
public interface IEmpiChannelSubmitterSvc {
/**
* TODO GGG write javadoc
* @param theResource
*/
void submitResourceToEmpiChannel(IBaseResource theResource);
}

View File

@ -1,8 +0,0 @@
package ca.uhn.fhir.empi.api;
import org.hl7.fhir.instance.model.api.IBaseResource;
public interface IEmpiQueueSubmitterSvc {
void manuallySubmitResourceToEmpi(IBaseResource theResource);
}

View File

@ -20,14 +20,15 @@ package ca.uhn.fhir.empi.api;
* #L%
*/
public interface IEmpiExpungeSvc {
public interface IEmpiResetSvc {
/**
* Given a resource type, delete the underlying empi links, and their related person objects.
*
* @param theResourceType The type of resources
*/
void expungeEmpiLinks(String theResourceType);
void expungeAllEmpiLinksOfTargetType(String theResourceType);
void expungeEmpiLinks();
void expungeAllEmpiLinks();
}

View File

@ -24,7 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.empi.api.EmpiLinkSourceEnum;
import ca.uhn.fhir.empi.api.EmpiMatchResultEnum;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkQuerySvc;
import ca.uhn.fhir.empi.api.IEmpiLinkUpdaterSvc;
import ca.uhn.fhir.empi.api.IEmpiMatchFinderSvc;
@ -54,7 +54,7 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
private final IEmpiPersonMergerSvc myPersonMergerSvc;
private final IEmpiLinkUpdaterSvc myEmpiLinkUpdaterSvc;
private final IEmpiLinkQuerySvc myEmpiLinkQuerySvc;
private final IEmpiExpungeSvc myEmpiExpungeSvc;
private final IEmpiResetSvc myEmpiExpungeSvc;
private final IEmpiBatchService myEmpiBatchService;
/**
@ -63,7 +63,7 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
* Note that this is not a spring bean. Any necessary injections should
* happen in the constructor
*/
public EmpiProviderDstu3(FhirContext theFhirContext, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiPersonMergerSvc thePersonMergerSvc, IEmpiLinkUpdaterSvc theEmpiLinkUpdaterSvc, IEmpiLinkQuerySvc theEmpiLinkQuerySvc, IResourceLoader theResourceLoader, IEmpiExpungeSvc theEmpiExpungeSvc, IEmpiBatchService theEmpiBatchSvc) {
public EmpiProviderDstu3(FhirContext theFhirContext, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiPersonMergerSvc thePersonMergerSvc, IEmpiLinkUpdaterSvc theEmpiLinkUpdaterSvc, IEmpiLinkQuerySvc theEmpiLinkQuerySvc, IResourceLoader theResourceLoader, IEmpiResetSvc theEmpiExpungeSvc, IEmpiBatchService theEmpiBatchSvc) {
super(theFhirContext, theResourceLoader);
myEmpiMatchFinderSvc = theEmpiMatchFinderSvc;
myPersonMergerSvc = thePersonMergerSvc;

View File

@ -23,7 +23,7 @@ package ca.uhn.fhir.empi.provider;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkQuerySvc;
import ca.uhn.fhir.empi.api.IEmpiLinkUpdaterSvc;
import ca.uhn.fhir.empi.api.IEmpiMatchFinderSvc;
@ -50,7 +50,7 @@ public class EmpiProviderLoader {
@Autowired
private IResourceLoader myResourceLoader;
@Autowired
private IEmpiExpungeSvc myEmpiExpungeSvc;
private IEmpiResetSvc myEmpiExpungeSvc;
@Autowired
private IEmpiBatchService myEmpiBatchSvc;

View File

@ -24,11 +24,11 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.empi.api.EmpiLinkSourceEnum;
import ca.uhn.fhir.empi.api.EmpiMatchResultEnum;
import ca.uhn.fhir.empi.api.IEmpiBatchService;
import ca.uhn.fhir.empi.api.IEmpiExpungeSvc;
import ca.uhn.fhir.empi.api.IEmpiLinkQuerySvc;
import ca.uhn.fhir.empi.api.IEmpiLinkUpdaterSvc;
import ca.uhn.fhir.empi.api.IEmpiMatchFinderSvc;
import ca.uhn.fhir.empi.api.IEmpiPersonMergerSvc;
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
@ -41,6 +41,7 @@ import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.InstantType;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Parameters;
@ -58,7 +59,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
private final IEmpiPersonMergerSvc myPersonMergerSvc;
private final IEmpiLinkUpdaterSvc myEmpiLinkUpdaterSvc;
private final IEmpiLinkQuerySvc myEmpiLinkQuerySvc;
private final IEmpiExpungeSvc myEmpiExpungeSvc;
private final IEmpiResetSvc myEmpiExpungeSvc;
private final IEmpiBatchService myEmpiBatchSvc;
/**
@ -67,7 +68,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
* Note that this is not a spring bean. Any necessary injections should
* happen in the constructor
*/
public EmpiProviderR4(FhirContext theFhirContext, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiPersonMergerSvc thePersonMergerSvc, IEmpiLinkUpdaterSvc theEmpiLinkUpdaterSvc, IEmpiLinkQuerySvc theEmpiLinkQuerySvc, IResourceLoader theResourceLoader, IEmpiExpungeSvc theEmpiExpungeSvc, IEmpiBatchService theEmpiBatchSvc) {
public EmpiProviderR4(FhirContext theFhirContext, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiPersonMergerSvc thePersonMergerSvc, IEmpiLinkUpdaterSvc theEmpiLinkUpdaterSvc, IEmpiLinkQuerySvc theEmpiLinkQuerySvc, IResourceLoader theResourceLoader, IEmpiResetSvc theEmpiExpungeSvc, IEmpiBatchService theEmpiBatchSvc) {
super(theFhirContext, theResourceLoader);
myEmpiMatchFinderSvc = theEmpiMatchFinderSvc;
myPersonMergerSvc = thePersonMergerSvc;
@ -129,10 +130,10 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
@Operation(name = ProviderConstants.EMPI_CLEAR)
public Parameters clearEmpiLinks(@OperationParam(name=ProviderConstants.EMPI_CLEAR_TARGET_TYPE, min = 0, max = 1) StringType theTargetType) {
if (theTargetType == null) {
myEmpiExpungeSvc.expungeEmpiLinks();
if (theTargetType == null || StringUtils.isBlank(theTargetType.getValue())) {
myEmpiExpungeSvc.expungeAllEmpiLinks();
} else {
myEmpiExpungeSvc.expungeEmpiLinks(theTargetType.getValueNotNull());
myEmpiExpungeSvc.expungeAllEmpiLinksOfTargetType(theTargetType.getValueNotNull());
}
return new Parameters();
}
@ -177,7 +178,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
@OperationParam(name= ProviderConstants.EMPI_BATCH_RUN_CRITERIA,min = 0 , max = 1) StringType theCriteria,
ServletRequestDetails theRequestDetails) {
String criteria = convertCriteriaToString(theCriteria);
int submittedCount = myEmpiBatchSvc.runEmpiOnAllTargetTypes(criteria);
long submittedCount = myEmpiBatchSvc.runEmpiOnAllTargetTypes(criteria);
return buildEmpiOutParametersWithCount(submittedCount);
}
@ -185,19 +186,13 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
return theCriteria == null ? null : theCriteria.getValueAsString();
}
private void validateCriteriaIsPresent(StringType theCriteria){
if (theCriteria == null || StringUtils.isBlank(theCriteria.getValue())) {
throw new InvalidRequestException("While executing " + ProviderConstants.OPERATION_EMPI_BATCH_RUN + " on a type or the server root, resource, the criteria parameter is mandatory.");
}
}
@Operation(name = ProviderConstants.OPERATION_EMPI_BATCH_RUN, idempotent = false, type = Patient.class, returnParameters = {
@OperationParam(name = ProviderConstants.OPERATION_EMPI_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = IntegerType.class)
})
public Parameters empiBatchPatientInstance(
@IdParam IIdType theIdParam,
RequestDetails theRequest) {
int submittedCount = myEmpiBatchSvc.runEmpiOnTargetPatient(theIdParam);
long submittedCount = myEmpiBatchSvc.runEmpiOnTarget(theIdParam);
return buildEmpiOutParametersWithCount(submittedCount);
}
@ -208,7 +203,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
RequestDetails theRequest) {
String criteria = convertCriteriaToString(theCriteria);
int submittedCount = myEmpiBatchSvc.runEmpiOnPatientType(criteria);
long submittedCount = myEmpiBatchSvc.runEmpiOnPatientType(criteria);
return buildEmpiOutParametersWithCount(submittedCount);
}
@ -218,7 +213,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
public Parameters empiBatchPractitionerInstance(
@IdParam IIdType theIdParam,
RequestDetails theRequest) {
int submittedCount = myEmpiBatchSvc.runEmpiOnTargetPractitioner(theIdParam);
long submittedCount = myEmpiBatchSvc.runEmpiOnTarget(theIdParam);
return buildEmpiOutParametersWithCount(submittedCount);
}
@ -229,18 +224,18 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
RequestDetails theRequest) {
String criteria = convertCriteriaToString(theCriteria);
int submittedCount = myEmpiBatchSvc.runEmpiOnPractitionerType(criteria);
long submittedCount = myEmpiBatchSvc.runEmpiOnPractitionerType(criteria);
return buildEmpiOutParametersWithCount(submittedCount);
}
/**
* Helper function to build the out-parameters for all batch EMPI operations.
*/
private Parameters buildEmpiOutParametersWithCount(int theCount) {
private Parameters buildEmpiOutParametersWithCount(long theCount) {
Parameters parameters = new Parameters();
parameters.addParameter()
.setName(ProviderConstants.OPERATION_EMPI_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT)
.setValue(new IntegerType(theCount));
.setValue(new DecimalType(theCount));
return parameters;
}
}

View File

@ -68,7 +68,6 @@ public class PointcutLatch implements IAnonymousInterceptor, IPointcutLatch {
}
public void runWithExpectedCount(int theExpectedCount, Runnable r) {
this.clear();
this.setExpectedCount(theExpectedCount);
r.run();
try {