2480 partition aware subscription (#3218)
* some fixmes to start
* Added some FIXMEs
* added RequestPartitionId to reosurceDelivryMessage and ResourceModifiedMessage
* ResourceDeliveryMessage and ResourceModifiedMessage tests
* fixed issue with test missing partitionHelperSvc mocked bean
* Added tests and implemented SubscriptionMatchingSubscriber for partition aware subscription
* modified implementation of partitionId in CanonicalSubscription
* Moved PartitionablePartitionId, and refactored all calls to getUserData(Constants.RESOURCE_PARTITION_ID) and setUserData(Constants.RESOURCE_PARTITION_ID)
* Revert "Moved PartitionablePartitionId, and refactored all calls to getUserData(Constants.RESOURCE_PARTITION_ID) and setUserData(Constants.RESOURCE_PARTITION_ID)"
This reverts commit fe40fb9733
.
* Got added partitionId to subscriptions, added changes to make SubscriptionMatchingSubscriberTest work
* added SubscriptionTriggering test, also added partition support to subscriptionLoader
* Changed implementation for storing partition id of subscriptions from messages, refactored tests to new implementation
* added all subscription systemRequestDetails with all partition to subscription reader
* refactored a generic system request details with default all partition request
* Added test for dao subscriptions, fixes to get the test working
* added partition support for latest version delivery
* added doc changes and changelog for multitenancy subscription
* cleanup and added partitioned subscription manually trigger test
* fixed mocked subscriptionDao
* added package-info for subscription module
* some code review changes
* removed AllPartitionSystemRequestDetail, added new text for multitenant subscription
* renamed method for code review
* version bump to 5.7.0PRE7
Co-authored-by: Michael Buckley <michael.buckley@smilecdr.com>
Co-authored-by: Ken Stevens <khstevens@gmail.com>
Co-authored-by: Long Ma <long@smilecdr.com>
Co-authored-by: Steven Li <steven@smilecdr.com>
This commit is contained in:
parent
d6e543a478
commit
a56603daa2
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: add
|
||||
issue: 2480
|
||||
title: "Added partition support for subscriptions. Subscriptions will now only match resource from the same partition"
|
|
@ -95,13 +95,13 @@ The following resource types may not be placed in any partition except the defau
|
|||
* CodeSystem
|
||||
* CompartmentDefinition
|
||||
* ConceptMap
|
||||
* Library
|
||||
* NamingSystem
|
||||
* OperationDefinition
|
||||
* Questionnaire
|
||||
* SearchParameter
|
||||
* StructureDefinition
|
||||
* StructureMap
|
||||
* Subscription
|
||||
* ValueSet
|
||||
|
||||
## Examples
|
||||
|
@ -150,19 +150,17 @@ None of the limitations listed here are considered permanent. Over time the HAPI
|
|||
* CodeSystem
|
||||
* CompartmentDefinition
|
||||
* ConceptMap
|
||||
* Library
|
||||
* NamingSystem
|
||||
* OperationDefinition
|
||||
* Questionnaire
|
||||
* SearchParameter
|
||||
* StructureDefinition
|
||||
* StructureMap
|
||||
* Subscription
|
||||
* ValueSet
|
||||
|
||||
* **Server Capability Statement is not partition aware**: The server creates and exposes a single server capability statement, covering all partitions. This can be misleading when partitioning us used as a multitenancy strategy.
|
||||
|
||||
* **Subscriptions may not be partitioned**: All subscriptions must be placed in the default partition, and subscribers will receive deliveries for any matching resources from all partitions.
|
||||
|
||||
* **Conformance resources may not be partitioned**: Conformance resources must be placed in the default partition, and will be shared for any validation activities across all partitions.
|
||||
|
||||
* **Search Parameters are not partitioned**: There is only one set of SearchParameter resources for the entire system, and any search parameters will apply to resources in all partitions. All SearchParameter resources must be stored in the default partition.
|
||||
|
@ -174,3 +172,5 @@ None of the limitations listed here are considered permanent. Over time the HAPI
|
|||
* **Package Operations are not partition aware**: Package operations will only create, update and query resources in the default partition.
|
||||
|
||||
* **Advanced Elasticsearch indexing is not partition optimized**: The results are correctly partitioned, but the extended indexing is not optimized to account for partitions.
|
||||
|
||||
* **Subscriptions are partition aware**: Subscriptions can be placed on any partition and will deliver matching resources from the same partition.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
|||
myNonPartitionableResourceNames = new HashSet<>();
|
||||
|
||||
// Infrastructure
|
||||
myNonPartitionableResourceNames.add("Subscription");
|
||||
myNonPartitionableResourceNames.add("SearchParameter");
|
||||
|
||||
// Validation and Conformance
|
||||
|
@ -85,6 +84,8 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
|||
myNonPartitionableResourceNames.add("CompartmentDefinition");
|
||||
myNonPartitionableResourceNames.add("OperationDefinition");
|
||||
|
||||
myNonPartitionableResourceNames.add("Library");
|
||||
|
||||
// Terminology
|
||||
myNonPartitionableResourceNames.add("ConceptMap");
|
||||
myNonPartitionableResourceNames.add("CodeSystem");
|
||||
|
|
|
@ -200,7 +200,7 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
|
|||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
|
||||
public RequestPartitionId PartitionIdentifyRead(ServletRequestDetails theRequestDetails) {
|
||||
public RequestPartitionId partitionIdentifyRead(ServletRequestDetails theRequestDetails) {
|
||||
RequestPartitionId retVal = myReadRequestPartitionIds.remove(0);
|
||||
ourLog.info("Returning partition for read: {}", retVal);
|
||||
return retVal;
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
package ca.uhn.fhir.jpa.partition;
|
||||
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
||||
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BasePartitioningR4Test;
|
||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR4Test;
|
||||
import ca.uhn.fhir.jpa.subscription.resthook.RestHookTestR4Test;
|
||||
import ca.uhn.fhir.jpa.subscription.triggering.ISubscriptionTriggeringSvc;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import org.awaitility.core.ConditionTimeoutException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class PartitionedSubscriptionTriggeringR4Test extends BaseSubscriptionsR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RestHookTestR4Test.class);
|
||||
|
||||
@Autowired
|
||||
StoppableSubscriptionDeliveringRestHookSubscriber myStoppableSubscriptionDeliveringRestHookSubscriber;
|
||||
|
||||
@Autowired
|
||||
private ISubscriptionTriggeringSvc mySubscriptionTriggeringSvc;
|
||||
|
||||
static final String PARTITION_1 = "PART-1";
|
||||
static final String PARTITION_2 = "PART-2";
|
||||
|
||||
protected MyReadWriteInterceptor myPartitionInterceptor;
|
||||
protected LocalDate myPartitionDate;
|
||||
protected LocalDate myPartitionDate2;
|
||||
protected int myPartitionId;
|
||||
protected int myPartitionId2;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() throws ServletException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionSettings.setIncludePartitionInSearchHashes(new PartitionSettings().isIncludePartitionInSearchHashes());
|
||||
|
||||
myDaoConfig.setUniqueIndexesEnabled(true);
|
||||
|
||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
|
||||
myPartitionDate = LocalDate.of(2020, Month.JANUARY, 14);
|
||||
myPartitionDate2 = LocalDate.of(2020, Month.JANUARY, 15);
|
||||
myPartitionId = 1;
|
||||
myPartitionId2 = 2;
|
||||
|
||||
myPartitionInterceptor = new MyReadWriteInterceptor();
|
||||
myPartitionInterceptor.setResultPartitionId(RequestPartitionId.fromPartitionNames(PARTITION_1));
|
||||
|
||||
mySrdInterceptorService.registerInterceptor(myPartitionInterceptor);
|
||||
|
||||
myPartitionConfigSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
||||
myPartitionConfigSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@Override
|
||||
public void afterUnregisterRestHookListener() {
|
||||
myStoppableSubscriptionDeliveringRestHookSubscriber.setCountDownLatch(null);
|
||||
myStoppableSubscriptionDeliveringRestHookSubscriber.unPause();
|
||||
myDaoConfig.setTriggerSubscriptionsForNonVersioningChanges(new DaoConfig().isTriggerSubscriptionsForNonVersioningChanges());
|
||||
|
||||
myDaoRegistry.getSystemDao().expunge(new ExpungeOptions().setExpungeEverything(true), null);
|
||||
|
||||
myPartitionSettings.setUnnamedPartitionMode(false);
|
||||
|
||||
mySrdInterceptorService.unregisterInterceptorsIf(t -> t instanceof BasePartitioningR4Test.MyReadWriteInterceptor);
|
||||
myInterceptor = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSubscriptionInPartition() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
Subscription subscription = newSubscription(criteria1, payload);
|
||||
|
||||
assertEquals(mySrdInterceptorService.getAllRegisteredInterceptors().size(), 1);
|
||||
|
||||
myDaoRegistry.getResourceDao("Subscription").create(subscription, mySrd);
|
||||
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
Observation observation = createBaseObservation(code, "SNOMED-CT");
|
||||
myDaoRegistry.getResourceDao("Observation").create(observation, mySrd);
|
||||
|
||||
// Should see 1 subscription notification
|
||||
waitForQueueToDrain();
|
||||
assertEquals(0, ourObservationProvider.getCountCreate());
|
||||
ourObservationProvider.waitForUpdateCount(1);
|
||||
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourRestfulServer.getRequestContentTypes().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSubscriptionInPartitionAndResourceInDifferentPartition() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Patient?active=true";
|
||||
Subscription subscription = newSubscription(criteria1, payload);
|
||||
|
||||
assertEquals(mySrdInterceptorService.getAllRegisteredInterceptors().size(), 1);
|
||||
|
||||
myDaoRegistry.getResourceDao("Subscription").create(subscription, mySrd);
|
||||
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
myDaoRegistry.getResourceDao("Patient").create(patient, new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.fromPartitionId(2)));
|
||||
|
||||
// Should see 0 subscription notification
|
||||
waitForQueueToDrain();
|
||||
assertEquals(0, ourPatientProvider.getCountCreate());
|
||||
|
||||
try {
|
||||
// Should have 0 matching subscription, if we get 1 update count then the test fails
|
||||
ourPatientProvider.waitForUpdateCount(1);
|
||||
fail();
|
||||
} catch (ConditionTimeoutException e) {
|
||||
assertEquals(0, ourRestfulServer.getRequestContentTypes().size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualTriggeredSubscriptionInPartition() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
// Create the resource first
|
||||
DaoMethodOutcome observationOutcome = myDaoRegistry.getResourceDao("Observation").create(createBaseObservation(code, "SNOMED-CT"), mySrd);
|
||||
|
||||
Observation observation = (Observation) observationOutcome.getResource();
|
||||
|
||||
// Create the subscription now
|
||||
DaoMethodOutcome subscriptionOutcome = myDaoRegistry.getResourceDao("Subscription").create(newSubscription(criteria1, payload), mySrd);
|
||||
|
||||
assertEquals(mySrdInterceptorService.getAllRegisteredInterceptors().size(), 1);
|
||||
|
||||
Subscription subscription = (Subscription) subscriptionOutcome.getResource();
|
||||
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
ArrayList<IPrimitiveType<String>> resourceIdList = new ArrayList<>();
|
||||
resourceIdList.add(observation.getIdElement());
|
||||
|
||||
|
||||
Parameters resultParameters = (Parameters) mySubscriptionTriggeringSvc.triggerSubscription(resourceIdList, null, subscription.getIdElement());
|
||||
|
||||
waitForQueueToDrain();
|
||||
assertEquals(0, ourObservationProvider.getCountCreate());
|
||||
|
||||
String responseValue = resultParameters.getParameter().get(0).getValue().primitiveValue();
|
||||
assertThat(responseValue, containsString("Subscription triggering job submitted as JOB ID"));
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
public static class MyReadWriteInterceptor {
|
||||
private RequestPartitionId myReadPartitionId;
|
||||
|
||||
public void setResultPartitionId(RequestPartitionId theRequestPartitionId) {
|
||||
myReadPartitionId = theRequestPartitionId;
|
||||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
|
||||
public RequestPartitionId read() {
|
||||
RequestPartitionId retVal = myReadPartitionId;
|
||||
ourLog.info("Returning partition for read: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
|
||||
public RequestPartitionId create() {
|
||||
RequestPartitionId retVal = myReadPartitionId;
|
||||
ourLog.info("Returning partition for write: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -142,20 +142,25 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
|||
}
|
||||
|
||||
|
||||
protected Observation sendObservation(String code, String system) {
|
||||
protected Observation sendObservation(String theCode, String theSystem) {
|
||||
Observation observation = createBaseObservation(theCode, theSystem);
|
||||
|
||||
IIdType id = myObservationDao.create(observation).getId();
|
||||
observation.setId(id);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
protected Observation createBaseObservation(String theCode, String theSystem) {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
observation.getIdentifierFirstRep().setSystem("foo").setValue("1");
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code);
|
||||
coding.setSystem(system);
|
||||
coding.setCode(theCode);
|
||||
coding.setSystem(theSystem);
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
IIdType id = myObservationDao.create(observation).getId();
|
||||
observation.setId(id);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public class ProducingChannelParameters extends BaseChannelParameters {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* <p>
|
||||
* Producing channels are sending channels. They send data to topics/queues.
|
||||
*
|
||||
* @param theChannelName
|
||||
|
|
|
@ -24,7 +24,7 @@ public class ReceivingChannelParameters extends BaseChannelParameters {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* <p>
|
||||
* Receiving channels are channels that receive data from topics/queues
|
||||
*
|
||||
* @param theChannelName
|
||||
|
|
|
@ -23,8 +23,10 @@ package ca.uhn.fhir.jpa.subscription.match.deliver.resthook;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
||||
|
@ -162,10 +164,11 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
|||
return operation;
|
||||
}
|
||||
|
||||
public IBaseResource getResource(IIdType payloadId) throws ResourceGoneException {
|
||||
public IBaseResource getResource(IIdType payloadId, RequestPartitionId thePartitionId) throws ResourceGoneException {
|
||||
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(payloadId.getResourceType());
|
||||
SystemRequestDetails systemRequestDetails = new SystemRequestDetails().setRequestPartitionId(thePartitionId);
|
||||
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceDef.getImplementingClass());
|
||||
return dao.read(payloadId.toVersionless());
|
||||
return dao.read(payloadId.toVersionless(), systemRequestDetails);
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,7 +180,7 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
|||
|
||||
try {
|
||||
if (payloadId != null) {
|
||||
payloadResource = getResource(payloadId.toVersionless());
|
||||
payloadResource = getResource(payloadId.toVersionless(), theMsg.getRequestPartitionId());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,15 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryMatchResult;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -37,7 +40,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
||||
private Logger ourLog = LoggerFactory.getLogger(DaoSubscriptionMatcher.class);
|
||||
private final Logger ourLog = LoggerFactory.getLogger(DaoSubscriptionMatcher.class);
|
||||
|
||||
@Autowired
|
||||
DaoRegistry myDaoRegistry;
|
||||
|
@ -56,7 +59,7 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
// Run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource
|
||||
criteria += "&_id=" + id.toUnqualifiedVersionless().getValue();
|
||||
|
||||
IBundleProvider results = performSearch(criteria);
|
||||
IBundleProvider results = performSearch(criteria, theSubscription);
|
||||
|
||||
ourLog.debug("Subscription check found {} results for query: {}", results.size(), criteria);
|
||||
|
||||
|
@ -66,7 +69,7 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
/**
|
||||
* Search based on a query criteria
|
||||
*/
|
||||
private IBundleProvider performSearch(String theCriteria) {
|
||||
private IBundleProvider performSearch(String theCriteria, CanonicalSubscription theSubscription) {
|
||||
IFhirResourceDao<?> subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
RuntimeResourceDefinition responseResourceDef = subscriptionDao.validateCriteriaAndReturnResourceDefinition(theCriteria);
|
||||
SearchParameterMap responseCriteriaUrl = myMatchUrlService.translateMatchUrl(theCriteria, responseResourceDef);
|
||||
|
@ -74,7 +77,9 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
IFhirResourceDao<? extends IBaseResource> responseDao = myDaoRegistry.getResourceDao(responseResourceDef.getImplementingClass());
|
||||
responseCriteriaUrl.setLoadSynchronousUpTo(1);
|
||||
|
||||
return responseDao.search(responseCriteriaUrl);
|
||||
PartitionablePartitionId partitionId = new PartitionablePartitionId(theSubscription.getRequestPartitionId(), null);
|
||||
RequestDetails systemRequestDetails = new SystemRequestDetails().setRequestPartitionId(partitionId.toPartitionId());
|
||||
return responseDao.search(responseCriteriaUrl, systemRequestDetails);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.subscription.match.matcher.subscriber;
|
|||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionConstants;
|
||||
|
@ -49,7 +50,7 @@ import javax.annotation.Nonnull;
|
|||
* Also validates criteria. If invalid, rejects the subscription without persisting the subscription.
|
||||
*/
|
||||
public class SubscriptionActivatingSubscriber extends BaseSubscriberForSubscriptionResources implements MessageHandler {
|
||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingSubscriber.class);
|
||||
private final Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingSubscriber.class);
|
||||
@Autowired
|
||||
private SubscriptionRegistry mySubscriptionRegistry;
|
||||
@Autowired
|
||||
|
@ -115,19 +116,21 @@ public class SubscriptionActivatingSubscriber extends BaseSubscriberForSubscript
|
|||
@SuppressWarnings("unchecked")
|
||||
private boolean activateSubscription(final IBaseResource theSubscription) {
|
||||
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
IBaseResource subscription = subscriptionDao.read(theSubscription.getIdElement());
|
||||
SystemRequestDetails srd = SystemRequestDetails.forAllPartition();
|
||||
|
||||
IBaseResource subscription = subscriptionDao.read(theSubscription.getIdElement(), SystemRequestDetails.forAllPartition());
|
||||
subscription.setId(subscription.getIdElement().toVersionless());
|
||||
|
||||
ourLog.info("Activating subscription {} from status {} to {}", subscription.getIdElement().toUnqualified().getValue(), SubscriptionConstants.REQUESTED_STATUS, SubscriptionConstants.ACTIVE_STATUS);
|
||||
try {
|
||||
SubscriptionUtil.setStatus(myFhirContext, subscription, SubscriptionConstants.ACTIVE_STATUS);
|
||||
subscriptionDao.update(subscription);
|
||||
subscriptionDao.update(subscription, srd);
|
||||
return true;
|
||||
} catch (final UnprocessableEntityException e) {
|
||||
ourLog.info("Changing status of {} to ERROR", subscription.getIdElement());
|
||||
SubscriptionUtil.setStatus(myFhirContext, subscription, "error");
|
||||
SubscriptionUtil.setReason(myFhirContext, subscription, e.getMessage());
|
||||
subscriptionDao.update(subscription);
|
||||
subscriptionDao.update(subscription, srd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
*/
|
||||
|
||||
public class SubscriptionMatchingSubscriber implements MessageHandler {
|
||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatchingSubscriber.class);
|
||||
private final Logger ourLog = LoggerFactory.getLogger(SubscriptionMatchingSubscriber.class);
|
||||
public static final String SUBSCRIPTION_MATCHING_CHANNEL_NAME = "subscription-matching";
|
||||
|
||||
@Autowired
|
||||
|
@ -123,7 +123,12 @@ public class SubscriptionMatchingSubscriber implements MessageHandler {
|
|||
boolean resourceMatched = false;
|
||||
|
||||
for (ActiveSubscription nextActiveSubscription : subscriptions) {
|
||||
|
||||
// skip if the partitions don't match
|
||||
CanonicalSubscription subscription = nextActiveSubscription.getSubscription();
|
||||
if (subscription != null && subscription.getRequestPartitionId() != null && theMsg.getPartitionId() != null
|
||||
&& !theMsg.getPartitionId().hasPartitionId(subscription.getRequestPartitionId())) {
|
||||
continue;
|
||||
}
|
||||
String nextSubscriptionId = getId(nextActiveSubscription);
|
||||
|
||||
if (isNotBlank(theMsg.getSubscriptionId())) {
|
||||
|
@ -154,15 +159,15 @@ public class SubscriptionMatchingSubscriber implements MessageHandler {
|
|||
}
|
||||
|
||||
IBaseResource payload = theMsg.getNewPayload(myFhirContext);
|
||||
CanonicalSubscription subscription = nextActiveSubscription.getSubscription();
|
||||
|
||||
EncodingEnum encoding = null;
|
||||
if (subscription.getPayloadString() != null && !subscription.getPayloadString().isEmpty()) {
|
||||
if (subscription != null && subscription.getPayloadString() != null && !subscription.getPayloadString().isEmpty()) {
|
||||
encoding = EncodingEnum.forContentType(subscription.getPayloadString());
|
||||
}
|
||||
encoding = defaultIfNull(encoding, EncodingEnum.JSON);
|
||||
|
||||
ResourceDeliveryMessage deliveryMsg = new ResourceDeliveryMessage();
|
||||
deliveryMsg.setPartitionId(theMsg.getPartitionId());
|
||||
|
||||
deliveryMsg.setPayload(myFhirContext, payload, encoding);
|
||||
deliveryMsg.setSubscription(subscription);
|
||||
|
|
|
@ -21,10 +21,15 @@ package ca.uhn.fhir.jpa.subscription.match.matcher.subscriber;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -42,13 +47,17 @@ import javax.annotation.Nonnull;
|
|||
* Also validates criteria. If invalid, rejects the subscription without persisting the subscription.
|
||||
*/
|
||||
public class SubscriptionRegisteringSubscriber extends BaseSubscriberForSubscriptionResources implements MessageHandler {
|
||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionRegisteringSubscriber.class);
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionRegisteringSubscriber.class);
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
@Autowired
|
||||
private SubscriptionRegistry mySubscriptionRegistry;
|
||||
@Autowired
|
||||
private SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
@Autowired
|
||||
private PartitionSettings myPartitionSettings;
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -77,9 +86,18 @@ public class SubscriptionRegisteringSubscriber extends BaseSubscriberForSubscrip
|
|||
case CREATE:
|
||||
case UPDATE:
|
||||
IBaseResource subscription = payload.getNewPayload(myFhirContext);
|
||||
IBaseResource subscriptionToRegister = subscription;
|
||||
String statusString = mySubscriptionCanonicalizer.getSubscriptionStatus(subscription);
|
||||
|
||||
// reading resource back from db in order to store partition id in the userdata of the resource for partitioned subscriptions
|
||||
if (myPartitionSettings.isPartitioningEnabled()) {
|
||||
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
RequestDetails systemRequestDetails = new SystemRequestDetails().setRequestPartitionId(payload.getPartitionId());
|
||||
subscriptionToRegister = subscriptionDao.read(subscription.getIdElement(), systemRequestDetails);
|
||||
}
|
||||
|
||||
if ("active".equals(statusString)) {
|
||||
mySubscriptionRegistry.registerSubscriptionUnlessAlreadyRegistered(payload.getNewPayload(myFhirContext));
|
||||
mySubscriptionRegistry.registerSubscriptionUnlessAlreadyRegistered(subscriptionToRegister);
|
||||
} else {
|
||||
mySubscriptionRegistry.unregisterSubscriptionIfRegistered(payload.getPayloadId(myFhirContext).getIdPart());
|
||||
}
|
||||
|
|
|
@ -27,13 +27,14 @@ import ca.uhn.fhir.jpa.cache.IResourceChangeListener;
|
|||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
|
||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -75,6 +76,7 @@ public class SubscriptionLoader implements IResourceChangeListener {
|
|||
private IResourceChangeListenerRegistry myResourceChangeListenerRegistry;
|
||||
|
||||
private SearchParameterMap mySearchParameterMap;
|
||||
private SystemRequestDetails mySystemRequestDetails;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -86,6 +88,8 @@ public class SubscriptionLoader implements IResourceChangeListener {
|
|||
@PostConstruct
|
||||
public void registerListener() {
|
||||
mySearchParameterMap = getSearchParameterMap();
|
||||
mySystemRequestDetails = SystemRequestDetails.forAllPartition();
|
||||
|
||||
IResourceChangeListenerCache subscriptionCache = myResourceChangeListenerRegistry.registerResourceResourceChangeListener("Subscription", mySearchParameterMap, this, REFRESH_INTERVAL);
|
||||
subscriptionCache.forceRefresh();
|
||||
}
|
||||
|
@ -142,7 +146,7 @@ public class SubscriptionLoader implements IResourceChangeListener {
|
|||
synchronized (mySyncSubscriptionsLock) {
|
||||
ourLog.debug("Starting sync subscriptions");
|
||||
|
||||
IBundleProvider subscriptionBundleList = getSubscriptionDao().search(mySearchParameterMap);
|
||||
IBundleProvider subscriptionBundleList = getSubscriptionDao().search(mySearchParameterMap, mySystemRequestDetails);
|
||||
|
||||
Integer subscriptionCount = subscriptionBundleList.size();
|
||||
assert subscriptionCount != null;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Module to support Subscriptions
|
||||
* <p>
|
||||
* Subscriptions are partition aware
|
||||
* <p>
|
||||
* The functionalities of this module follows the HL7 spec on Subscriptions:
|
||||
* http://hl7.org/fhir/subscription.html
|
||||
* <p>
|
||||
* Activated by {@link ca.uhn.fhir.jpa.model.config.PartitionSettings#setPartitioningEnabled(boolean)}
|
||||
*/
|
||||
package ca.uhn.fhir.jpa.subscription;
|
|
@ -6,7 +6,9 @@ import ca.uhn.fhir.interceptor.api.HookParams;
|
|||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.IResourceModifiedConsumer;
|
||||
|
@ -60,6 +62,8 @@ public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer
|
|||
private SubscriptionChannelFactory mySubscriptionChannelFactory;
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
|
||||
|
||||
private volatile MessageChannel myMatchingChannel;
|
||||
|
||||
|
@ -114,7 +118,9 @@ public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer
|
|||
*/
|
||||
@Override
|
||||
public void submitResourceModified(IBaseResource theNewResource, ResourceModifiedMessage.OperationTypeEnum theOperationType, RequestDetails theRequest) {
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theNewResource, theOperationType, theRequest);
|
||||
// Even though the resource is being written, the subscription will be interacting with it by effectively "reading" it so we set the RequestPartitionId as a read request
|
||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequestForRead(theRequest, theNewResource.getIdElement().getResourceType(), theNewResource.getIdElement());
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theNewResource, theOperationType, theRequest, requestPartitionId);
|
||||
|
||||
// Interceptor call: SUBSCRIPTION_RESOURCE_MODIFIED
|
||||
HookParams params = new HookParams()
|
||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
|
|||
import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.IResourceModifiedConsumer;
|
||||
|
@ -114,7 +115,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
if (!subscriptionId.hasResourceType()) {
|
||||
subscriptionId = subscriptionId.withResourceType(ResourceTypeEnum.SUBSCRIPTION.getCode());
|
||||
}
|
||||
subscriptionDao.read(subscriptionId);
|
||||
subscriptionDao.read(subscriptionId, SystemRequestDetails.forAllPartition());
|
||||
}
|
||||
|
||||
List<IPrimitiveType<String>> resourceIds = ObjectUtils.defaultIfNull(theResourceIds, Collections.emptyList());
|
||||
|
@ -298,7 +299,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
private Future<Void> submitResource(String theSubscriptionId, String theResourceIdToTrigger) {
|
||||
org.hl7.fhir.r4.model.IdType resourceId = new org.hl7.fhir.r4.model.IdType(theResourceIdToTrigger);
|
||||
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceId.getResourceType());
|
||||
IBaseResource resourceToTrigger = dao.read(resourceId);
|
||||
IBaseResource resourceToTrigger = dao.read(resourceId, SystemRequestDetails.forAllPartition());
|
||||
|
||||
return submitResource(theSubscriptionId, resourceToTrigger);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.subscription.match.deliver;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.subscription.match.deliver.resthook.SubscriptionDeliveringRestHookSubscriber;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
|
@ -13,19 +14,28 @@ import ca.uhn.fhir.rest.api.EncodingEnum;
|
|||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
@ -35,9 +45,10 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class BaseSubscriptionDeliverySubscriberTest {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseSubscriptionDeliverySubscriberTest.class);
|
||||
|
||||
private SubscriptionDeliveringRestHookSubscriber mySubscriber;
|
||||
private FhirContext myCtx = FhirContext.forR4();
|
||||
private final FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
@Mock
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
@ -79,13 +90,9 @@ public class BaseSubscriptionDeliverySubscriberTest {
|
|||
public void testRestHookDeliverySuccessful() {
|
||||
when(myInterceptorBroadcaster.callHooks(any(), any())).thenReturn(true);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
Patient patient = generatePatient();
|
||||
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setIdElement(new IdType("Subscription/123"));
|
||||
subscription.setEndpointUrl("http://example.com/fhir");
|
||||
subscription.setPayloadString("application/fhir+json");
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
|
||||
ResourceDeliveryMessage payload = new ResourceDeliveryMessage();
|
||||
payload.setSubscription(subscription);
|
||||
|
@ -101,13 +108,9 @@ public class BaseSubscriptionDeliverySubscriberTest {
|
|||
public void testRestHookDeliveryFails_ShouldRollBack() {
|
||||
when(myInterceptorBroadcaster.callHooks(any(), any())).thenReturn(true);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
Patient patient = generatePatient();
|
||||
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setIdElement(new IdType("Subscription/123"));
|
||||
subscription.setEndpointUrl("http://example.com/fhir");
|
||||
subscription.setPayloadString("application/fhir+json");
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
|
||||
ResourceDeliveryMessage payload = new ResourceDeliveryMessage();
|
||||
payload.setSubscription(subscription);
|
||||
|
@ -132,13 +135,9 @@ public class BaseSubscriptionDeliverySubscriberTest {
|
|||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY), any())).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_AFTER_DELIVERY_FAILED), any())).thenReturn(false);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
Patient patient = generatePatient();
|
||||
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setIdElement(new IdType("Subscription/123"));
|
||||
subscription.setEndpointUrl("http://example.com/fhir");
|
||||
subscription.setPayloadString("application/fhir+json");
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
|
||||
ResourceDeliveryMessage payload = new ResourceDeliveryMessage();
|
||||
payload.setSubscription(subscription);
|
||||
|
@ -158,13 +157,9 @@ public class BaseSubscriptionDeliverySubscriberTest {
|
|||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_BEFORE_DELIVERY), any())).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY), any())).thenReturn(false);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
Patient patient = generatePatient();
|
||||
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setIdElement(new IdType("Subscription/123"));
|
||||
subscription.setEndpointUrl("http://example.com/fhir");
|
||||
subscription.setPayloadString("application/fhir+json");
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
|
||||
ResourceDeliveryMessage payload = new ResourceDeliveryMessage();
|
||||
payload.setSubscription(subscription);
|
||||
|
@ -181,4 +176,77 @@ public class BaseSubscriptionDeliverySubscriberTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeDeliveryMessageWithRequestPartition() throws JsonProcessingException {
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
Patient patient = generatePatient();
|
||||
|
||||
ResourceDeliveryMessage message = new ResourceDeliveryMessage();
|
||||
message.setPartitionId(RequestPartitionId.fromPartitionId(123, LocalDate.of(2020, 1, 1)));
|
||||
message.setSubscription(subscription);
|
||||
message.setPayload(myCtx, patient, EncodingEnum.JSON);
|
||||
message.setOperationType(ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
|
||||
ResourceDeliveryJsonMessage jsonMessage = new ResourceDeliveryJsonMessage(message);
|
||||
String jsonString = jsonMessage.asJson();
|
||||
|
||||
ourLog.info(jsonString);
|
||||
|
||||
|
||||
|
||||
// Assert that the partitionID is being serialized in JSON
|
||||
assertThat(jsonString, containsString("\"partitionDate\":[2020,1,1]"));
|
||||
assertThat(jsonString, containsString("\"partitionIds\":[123]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeDeliveryMessageWithNoPartition() throws JsonProcessingException {
|
||||
CanonicalSubscription subscription = generateSubscription();
|
||||
Patient patient = generatePatient();
|
||||
|
||||
ResourceDeliveryMessage message = new ResourceDeliveryMessage();
|
||||
message.setSubscription(subscription);
|
||||
message.setPayload(myCtx, patient, EncodingEnum.JSON);
|
||||
message.setOperationType(ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
|
||||
ResourceDeliveryJsonMessage jsonMessage = new ResourceDeliveryJsonMessage(message);
|
||||
String jsonString = jsonMessage.asJson();
|
||||
|
||||
ourLog.info(jsonString);
|
||||
|
||||
assertThat(jsonString, containsString("\"operationType\":\"CREATE"));
|
||||
assertThat(jsonString, containsString("\"canonicalSubscription\":"));
|
||||
|
||||
// Assert that the default partitionID is being generated and is being serialized in JSON
|
||||
assertThat(jsonString, containsString("\"allPartitions\":false"));
|
||||
assertThat(jsonString, containsString("\"partitionIds\":[null]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeLegacyDeliveryMessage() throws JsonProcessingException {
|
||||
String legacyDeliveryMessageJson = "{\"headers\":{\"retryCount\":0,\"customHeaders\":{}},\"payload\":{\"operationType\":\"CREATE\",\"canonicalSubscription\":{\"id\":\"Subscription/123\",\"endpointUrl\":\"http://example.com/fhir\",\"payload\":\"application/fhir+json\"},\"payload\":\"{\\\"resourceType\\\":\\\"Patient\\\",\\\"active\\\":true}\"}}";
|
||||
|
||||
ResourceDeliveryJsonMessage jsonMessage = ResourceDeliveryJsonMessage.fromJson(legacyDeliveryMessageJson);
|
||||
|
||||
ourLog.info(jsonMessage.getPayload().getRequestPartitionId().asJson());
|
||||
|
||||
assertNotNull(jsonMessage.getPayload().getRequestPartitionId());
|
||||
assertEquals(jsonMessage.getPayload().getRequestPartitionId().toJson(), RequestPartitionId.defaultPartition().toJson());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Patient generatePatient() {
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
return patient;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CanonicalSubscription generateSubscription() {
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setIdElement(new IdType("Subscription/123"));
|
||||
subscription.setEndpointUrl("http://example.com/fhir");
|
||||
subscription.setPayloadString("application/fhir+json");
|
||||
return subscription;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
@ -22,6 +25,7 @@ public class ResourceModifiedTest {
|
|||
Organization decodedOrg = (Organization) msg.getNewPayload(myFhirContext);
|
||||
assertEquals(org.getId(), decodedOrg.getId());
|
||||
assertEquals(org.getName(), decodedOrg.getName());
|
||||
assertEquals(msg.getPartitionId().toJson(), RequestPartitionId.defaultPartition().toJson());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -35,6 +39,7 @@ public class ResourceModifiedTest {
|
|||
Organization decodedOrg = (Organization) msg.getNewPayload(myFhirContext);
|
||||
assertEquals(org.getId(), decodedOrg.getId());
|
||||
assertEquals(org.getName(), decodedOrg.getName());
|
||||
assertEquals(msg.getPartitionId().toJson(), RequestPartitionId.defaultPartition().toJson());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -46,6 +51,19 @@ public class ResourceModifiedTest {
|
|||
assertEquals("Organization/testOrgId", msg.getPayloadId(myFhirContext).getValue());
|
||||
assertEquals(ResourceModifiedMessage.OperationTypeEnum.DELETE, msg.getOperationType());
|
||||
assertNull(msg.getNewPayload(myFhirContext));
|
||||
assertEquals(msg.getPartitionId().toJson(), RequestPartitionId.defaultPartition().toJson());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithPartition() {
|
||||
Organization org = new Organization();
|
||||
org.setName("testOrgName");
|
||||
org.setId("Organization/testOrgId");
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, org, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
msg.setPartitionId(RequestPartitionId.fromPartitionId(123, LocalDate.of(2020, 1, 1)));
|
||||
|
||||
assertEquals(msg.getPartitionId().getPartitionIds().size(), 1);
|
||||
assertEquals(msg.getPartitionId().getPartitionIds().get(0), 123);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
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.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelConsumerSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.ISubscriptionDeliveryChannelNamer;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory;
|
||||
|
@ -40,6 +45,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -59,6 +65,8 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
|
||||
@Autowired
|
||||
FhirContext myFhirContext;
|
||||
@Autowired
|
||||
protected DaoRegistry myDaoRegistry;
|
||||
|
||||
// Caused by: java.lang.IllegalStateException: Unable to register mock bean org.springframework.messaging.MessageHandler expected a single matching bean to replace but found [subscriptionActivatingSubscriber, subscriptionDeliveringEmailSubscriber, subscriptionDeliveringRestHookSubscriber, subscriptionMatchingSubscriber, subscriptionRegisteringSubscriber]
|
||||
|
||||
|
@ -82,6 +90,8 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
private SubscriptionLoader mySubscriptionLoader;
|
||||
@Autowired
|
||||
private ISubscriptionDeliveryChannelNamer mySubscriptionDeliveryChannelNamer;
|
||||
@Autowired
|
||||
protected PartitionSettings myPartitionSettings;
|
||||
|
||||
protected String myCode = "1000000050";
|
||||
|
||||
|
@ -96,6 +106,8 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
protected final PointcutLatch mySubscriptionMatchingPost = new PointcutLatch(Pointcut.SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED);
|
||||
protected final PointcutLatch mySubscriptionActivatedPost = new PointcutLatch(Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED);
|
||||
protected final PointcutLatch mySubscriptionAfterDelivery = new PointcutLatch(Pointcut.SUBSCRIPTION_AFTER_DELIVERY);
|
||||
protected final PointcutLatch mySubscriptionResourceMatched = new PointcutLatch(Pointcut.SUBSCRIPTION_RESOURCE_MATCHED);
|
||||
protected final PointcutLatch mySubscriptionResourceNotMatched = new PointcutLatch(Pointcut.SUBSCRIPTION_RESOURCE_DID_NOT_MATCH_ANY_SUBSCRIPTIONS);
|
||||
|
||||
@BeforeEach
|
||||
public void beforeReset() {
|
||||
|
@ -113,10 +125,13 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED, mySubscriptionMatchingPost);
|
||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED, mySubscriptionActivatedPost);
|
||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.SUBSCRIPTION_AFTER_DELIVERY, mySubscriptionAfterDelivery);
|
||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.SUBSCRIPTION_RESOURCE_MATCHED, mySubscriptionResourceMatched);
|
||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.SUBSCRIPTION_RESOURCE_DID_NOT_MATCH_ANY_SUBSCRIPTIONS, mySubscriptionResourceNotMatched);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() {
|
||||
myPartitionSettings.setPartitioningEnabled(false);
|
||||
myInterceptorRegistry.unregisterAllInterceptors();
|
||||
mySubscriptionMatchingPost.clear();
|
||||
mySubscriptionActivatedPost.clear();
|
||||
|
@ -125,7 +140,11 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
}
|
||||
|
||||
public <T extends IBaseResource> T sendResource(T theResource) throws InterruptedException {
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
return sendResource(theResource, null);
|
||||
}
|
||||
|
||||
public <T extends IBaseResource> T sendResource(T theResource, RequestPartitionId theRequestPartitionId) throws InterruptedException {
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE, null, theRequestPartitionId);
|
||||
ResourceModifiedJsonMessage message = new ResourceModifiedJsonMessage(msg);
|
||||
mySubscriptionMatchingPost.setExpectedCount(1);
|
||||
ourSubscribableChannel.send(message);
|
||||
|
@ -133,15 +152,18 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
return theResource;
|
||||
}
|
||||
|
||||
protected Subscription sendSubscription(String theCriteria, String thePayload, String theEndpoint) throws InterruptedException {
|
||||
Subscription subscription = makeActiveSubscription(theCriteria, thePayload, theEndpoint);
|
||||
protected Subscription sendSubscription(Subscription theSubscription, RequestPartitionId theRequestPartitionId, Boolean mockDao) throws InterruptedException {
|
||||
mySubscriptionActivatedPost.setExpectedCount(1);
|
||||
Subscription retval = sendResource(subscription);
|
||||
Subscription retVal = sendResource(theSubscription, theRequestPartitionId);
|
||||
mySubscriptionActivatedPost.awaitExpected();
|
||||
return retval;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected Observation sendObservation(String code, String system) throws InterruptedException {
|
||||
return sendObservation(code, system, null);
|
||||
}
|
||||
|
||||
protected Observation sendObservation(String code, String system, RequestPartitionId theRequestPartitionId) throws InterruptedException {
|
||||
Observation observation = new Observation();
|
||||
IdType id = new IdType("Observation", nextId());
|
||||
observation.setId(id);
|
||||
|
@ -154,7 +176,7 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
return sendResource(observation);
|
||||
return sendResource(observation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
|
@ -224,6 +246,8 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
}
|
||||
|
||||
@Override
|
||||
public void clear() { updateLatch.clear();}
|
||||
public void clear() {
|
||||
updateLatch.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.hl7.fhir.dstu3.model.CodeableConcept;
|
|||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -26,8 +27,10 @@ public class SubscriptionCheckingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -47,8 +50,10 @@ public class SubscriptionCheckingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -68,8 +73,10 @@ public class SubscriptionCheckingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code;
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -90,8 +97,10 @@ public class SubscriptionCheckingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
|
|
@ -1,19 +1,37 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.subscription.module.standalone.BaseBlockingQueueSubscribableChannelDstu3Test;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
|
||||
/**
|
||||
* Tests copied from jpa.subscription.resthook.RestHookTestDstu3Test
|
||||
*/
|
||||
public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscribableChannelDstu3Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionMatchingSubscriberTest.class);
|
||||
private final IFhirResourceDao<Subscription> myMockSubscriptionDao = Mockito.mock(IFhirResourceDao.class);
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
Mockito.when(myMockSubscriptionDao.getResourceType()).thenReturn(Subscription.class);
|
||||
myDaoRegistry.register(myMockSubscriptionDao);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationFhirJson() throws Exception {
|
||||
|
@ -23,8 +41,10 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -44,8 +64,10 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -59,16 +81,16 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
|
||||
@Test
|
||||
public void testRestHookSubscription_NoResourceTypeInPayloadId() throws Exception {
|
||||
sendSubscription("Observation?", "application/fhir+xml", ourListenerServerBase);
|
||||
|
||||
assertEquals(1, mySubscriptionRegistry.size());
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
|
||||
Observation observation = new Observation();
|
||||
observation.setId("OBS");
|
||||
observation.setStatus(Observation.ObservationStatus.CORRECTED);
|
||||
sendResource(observation);
|
||||
|
||||
Subscription subscription = makeActiveSubscription("Observation?", "application/fhir+xml", ourListenerServerBase);
|
||||
sendSubscription(subscription, null, false);
|
||||
|
||||
assertEquals(1, mySubscriptionRegistry.size());
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
sendResource(observation);
|
||||
ourObservationListener.awaitExpected();
|
||||
|
||||
assertEquals(1, ourContentTypes.size());
|
||||
|
@ -83,8 +105,10 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria1 = "Observation?code=SNOMED-CT|" + code;
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111";
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
|
||||
assertEquals(2, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -107,9 +131,12 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
String criteria2 = "[*]";
|
||||
String criteria3 = "Observation?code=FOO"; // won't match
|
||||
|
||||
sendSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(criteria3, payload, ourListenerServerBase);
|
||||
Subscription subscription1 = makeActiveSubscription(criteria1, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription1, null, false);
|
||||
Subscription subscription2 = makeActiveSubscription(criteria2, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription2, null, false);
|
||||
Subscription subscription3 = makeActiveSubscription(criteria3, payload, ourListenerServerBase);
|
||||
sendSubscription(subscription3, null, false);
|
||||
|
||||
assertEquals(3, mySubscriptionRegistry.size());
|
||||
|
||||
|
@ -121,5 +148,127 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
assertEquals(Constants.CT_FHIR_XML_NEW, ourContentTypes.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionAndResourceOnTheSamePartitionMatch() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(0);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
mySubscriptionResourceMatched.setExpectedCount(1);
|
||||
sendObservation(code, "SNOMED-CT", requestPartitionId);
|
||||
mySubscriptionResourceMatched.awaitExpected();
|
||||
ourObservationListener.awaitExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionAndResourceOnTheSamePartitionMatchPart2() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
mySubscriptionResourceMatched.setExpectedCount(1);
|
||||
sendObservation(code, "SNOMED-CT", requestPartitionId);
|
||||
mySubscriptionResourceMatched.awaitExpected();
|
||||
ourObservationListener.awaitExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionAndResourceOnDiffPartitionNotMatch() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
mySubscriptionResourceNotMatched.setExpectedCount(1);
|
||||
sendObservation(code, "SNOMED-CT", RequestPartitionId.fromPartitionId(0));
|
||||
mySubscriptionResourceNotMatched.awaitExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionAndResourceOnDiffPartitionNotMatchPart2() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(0);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
mySubscriptionResourceNotMatched.setExpectedCount(1);
|
||||
sendObservation(code, "SNOMED-CT", RequestPartitionId.fromPartitionId(1));
|
||||
mySubscriptionResourceNotMatched.awaitExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionOnOnePartitionMatchResourceOnMultiplePartitions() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
mySubscriptionResourceMatched.setExpectedCount(1);
|
||||
List<Integer> partitionId = Collections.synchronizedList(Lists.newArrayList(0, 1, 2));
|
||||
sendObservation(code, "SNOMED-CT", RequestPartitionId.fromPartitionIds(partitionId));
|
||||
mySubscriptionResourceMatched.awaitExpected();
|
||||
ourObservationListener.awaitExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionOnOnePartitionDoNotMatchResourceOnMultiplePartitions() throws InterruptedException {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||
Subscription subscription = makeActiveSubscription(criteria, payload, ourListenerServerBase);
|
||||
mockSubscriptionRead(requestPartitionId, subscription);
|
||||
sendSubscription(subscription, requestPartitionId, true);
|
||||
|
||||
mySubscriptionResourceNotMatched.setExpectedCount(1);
|
||||
List<Integer> partitionId = Collections.synchronizedList(Lists.newArrayList(0, 2));
|
||||
sendObservation(code, "SNOMED-CT", RequestPartitionId.fromPartitionIds(partitionId));
|
||||
mySubscriptionResourceNotMatched.awaitExpected();
|
||||
}
|
||||
|
||||
|
||||
private void mockSubscriptionRead(RequestPartitionId theRequestPartitionId, Subscription subscription) {
|
||||
Subscription modifiedSubscription = subscription.copy();
|
||||
// the original partition info was the request info, but we need the actual storage partition.
|
||||
modifiedSubscription.setUserData(Constants.RESOURCE_PARTITION_ID, theRequestPartitionId);
|
||||
Mockito.when(myMockSubscriptionDao.read(eq(subscription.getIdElement()), any())).thenReturn(modifiedSubscription);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.cache.IResourceVersionSvc;
|
|||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.config.SearchParamConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory;
|
||||
|
@ -53,6 +54,8 @@ public class SubscriptionSubmitInterceptorLoaderTest {
|
|||
private SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
||||
@MockBean
|
||||
private IResourceVersionSvc myResourceVersionSvc;
|
||||
@MockBean
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
|
||||
|
||||
/**
|
||||
* It should be possible to run only the {@link SubscriptionSubmitterConfig} without the
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -57,6 +57,10 @@ public class SystemRequestDetails extends RequestDetails {
|
|||
super(new MyInterceptorBroadcaster());
|
||||
}
|
||||
|
||||
public static SystemRequestDetails forAllPartition(){
|
||||
return new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.allPartitions());
|
||||
}
|
||||
|
||||
private ListMultimap<String, String> myHeaders;
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,15 +22,15 @@ package ca.uhn.fhir.jpa.subscription.match.registry;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
|
@ -46,7 +46,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -124,6 +123,7 @@ public class SubscriptionCanonicalizer {
|
|||
if (status != null) {
|
||||
retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(status.toCode()));
|
||||
}
|
||||
setPartitionIdOnReturnValue(theSubscription, retVal);
|
||||
retVal.setChannelType(getChannelType(theSubscription));
|
||||
retVal.setCriteriaString(subscription.getCriteria());
|
||||
retVal.setEndpointUrl(subscription.getChannel().getEndpoint());
|
||||
|
@ -232,6 +232,7 @@ public class SubscriptionCanonicalizer {
|
|||
retVal.setPayloadString(subscription.getChannel().getPayload());
|
||||
retVal.setPayloadSearchCriteria(getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA));
|
||||
retVal.setTags(extractTags(subscription));
|
||||
setPartitionIdOnReturnValue(theSubscription, retVal);
|
||||
|
||||
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
||||
String from;
|
||||
|
@ -278,6 +279,7 @@ public class SubscriptionCanonicalizer {
|
|||
if (status != null) {
|
||||
retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(status.toCode()));
|
||||
}
|
||||
setPartitionIdOnReturnValue(theSubscription, retVal);
|
||||
retVal.setChannelType(getChannelType(subscription));
|
||||
retVal.setCriteriaString(getCriteria(theSubscription));
|
||||
retVal.setEndpointUrl(subscription.getEndpoint());
|
||||
|
@ -325,6 +327,13 @@ public class SubscriptionCanonicalizer {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private void setPartitionIdOnReturnValue(IBaseResource theSubscription, CanonicalSubscription retVal) {
|
||||
RequestPartitionId requestPartitionId = (RequestPartitionId) theSubscription.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||
if (requestPartitionId != null) {
|
||||
retVal.setPartitionId(requestPartitionId.getFirstPartitionIdOrNull());
|
||||
}
|
||||
}
|
||||
|
||||
private String getExtensionString(IBaseHasExtensions theBase, String theUrl) {
|
||||
return theBase
|
||||
.getExtension()
|
||||
|
|
|
@ -43,7 +43,6 @@ import java.util.Map;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class CanonicalSubscription implements Serializable, Cloneable, IModelJson {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty("id")
|
||||
|
@ -72,6 +71,8 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
|||
private Map<String, String> myTags;
|
||||
@JsonProperty("payloadSearchCriteria")
|
||||
private String myPayloadSearchCriteria;
|
||||
@JsonProperty("partitionId")
|
||||
private Integer myPartitionId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -89,7 +90,7 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
|||
}
|
||||
|
||||
/**
|
||||
* For now we're using the R4 TriggerDefinition, but this
|
||||
* For now, we're using the R4 TriggerDefinition, but this
|
||||
* may change in the future when things stabilize
|
||||
*/
|
||||
public void addTrigger(CanonicalEventDefinition theTrigger) {
|
||||
|
@ -159,9 +160,9 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
|||
|
||||
public String getChannelExtension(String theUrl) {
|
||||
String retVal = null;
|
||||
List<String> strings = myChannelExtensions.get(theUrl);
|
||||
if (strings != null && strings.isEmpty() == false) {
|
||||
retVal = strings.get(0);
|
||||
List<String> channelExtensions = myChannelExtensions.get(theUrl);
|
||||
if (channelExtensions != null && !channelExtensions.isEmpty()) {
|
||||
retVal = channelExtensions.get(0);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
@ -227,8 +228,16 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
|||
myStatus = theStatus;
|
||||
}
|
||||
|
||||
public Integer getRequestPartitionId() {
|
||||
return myPartitionId;
|
||||
}
|
||||
|
||||
public void setPartitionId(Integer thePartitionId) {
|
||||
myPartitionId = thePartitionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* For now we're using the R4 triggerdefinition, but this
|
||||
* For now, we're using the R4 triggerdefinition, but this
|
||||
* may change in the future when things stabilize
|
||||
*/
|
||||
public CanonicalEventDefinition getTrigger() {
|
||||
|
@ -325,7 +334,7 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
|||
private String mySubjectTemplate;
|
||||
|
||||
/**
|
||||
* Construcor
|
||||
* Constructor
|
||||
*/
|
||||
public EmailDetails() {
|
||||
super();
|
||||
|
|
|
@ -22,9 +22,12 @@ package ca.uhn.fhir.jpa.subscription.model;
|
|||
|
||||
import ca.uhn.fhir.rest.server.messaging.json.BaseJsonMessage;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
public class ResourceDeliveryJsonMessage extends BaseJsonMessage<ResourceDeliveryMessage> {
|
||||
private static final ObjectMapper ourObjectMapper = new ObjectMapper().registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
|
||||
|
||||
@JsonProperty("payload")
|
||||
private ResourceDeliveryMessage myPayload;
|
||||
|
@ -58,4 +61,12 @@ public class ResourceDeliveryJsonMessage extends BaseJsonMessage<ResourceDeliver
|
|||
.append("myPayload", myPayload)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static ResourceDeliveryJsonMessage fromJson(String theJson) throws JsonProcessingException {
|
||||
return ourObjectMapper.readValue(theJson, ResourceDeliveryJsonMessage.class);
|
||||
}
|
||||
|
||||
public String asJson() throws JsonProcessingException {
|
||||
return ourObjectMapper.writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.subscription.model;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.messaging.BaseResourceMessage;
|
||||
|
@ -38,6 +39,8 @@ public class ResourceDeliveryMessage extends BaseResourceMessage implements IRes
|
|||
|
||||
@JsonProperty("canonicalSubscription")
|
||||
private CanonicalSubscription mySubscription;
|
||||
@JsonProperty("partitionId")
|
||||
private RequestPartitionId myPartitionId;
|
||||
@JsonProperty("payload")
|
||||
private String myPayloadString;
|
||||
@JsonProperty("payloadId")
|
||||
|
@ -50,6 +53,7 @@ public class ResourceDeliveryMessage extends BaseResourceMessage implements IRes
|
|||
*/
|
||||
public ResourceDeliveryMessage() {
|
||||
super();
|
||||
myPartitionId = RequestPartitionId.defaultPartition();
|
||||
}
|
||||
|
||||
public IBaseResource getPayload(FhirContext theCtx) {
|
||||
|
@ -110,6 +114,14 @@ public class ResourceDeliveryMessage extends BaseResourceMessage implements IRes
|
|||
}
|
||||
}
|
||||
|
||||
public RequestPartitionId getRequestPartitionId() {
|
||||
return myPartitionId;
|
||||
}
|
||||
|
||||
public void setPartitionId(RequestPartitionId thePartitionId) {
|
||||
myPartitionId = thePartitionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
|
@ -117,6 +129,7 @@ public class ResourceDeliveryMessage extends BaseResourceMessage implements IRes
|
|||
.append("myPayloadString", myPayloadString)
|
||||
.append("myPayload", myPayloadDecoded)
|
||||
.append("myPayloadId", myPayloadId)
|
||||
.append("myPartitionId", myPartitionId)
|
||||
.append("myOperationType", getOperationType())
|
||||
.toString();
|
||||
}
|
||||
|
|
|
@ -21,14 +21,13 @@ package ca.uhn.fhir.jpa.subscription.model;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.messaging.BaseResourceModifiedMessage;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Most of this class has been moved to ResourceModifiedMessage in the hapi-fhir-server project, for a reusable channel ResourceModifiedMessage
|
||||
* that doesn't require knowledge of subscriptions.
|
||||
|
@ -42,6 +41,8 @@ public class ResourceModifiedMessage extends BaseResourceModifiedMessage {
|
|||
@JsonProperty(value = "subscriptionId", required = false)
|
||||
private String mySubscriptionId;
|
||||
|
||||
@JsonProperty(value = "partitionId", required = false)
|
||||
private RequestPartitionId myPartitionId;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -53,10 +54,17 @@ public class ResourceModifiedMessage extends BaseResourceModifiedMessage {
|
|||
|
||||
public ResourceModifiedMessage(FhirContext theFhirContext, IBaseResource theResource, OperationTypeEnum theOperationType) {
|
||||
super(theFhirContext, theResource, theOperationType);
|
||||
myPartitionId = RequestPartitionId.defaultPartition();
|
||||
}
|
||||
|
||||
public ResourceModifiedMessage(FhirContext theFhirContext, IBaseResource theNewResource, OperationTypeEnum theOperationType, RequestDetails theRequest) {
|
||||
super(theFhirContext, theNewResource, theOperationType, theRequest);
|
||||
myPartitionId = RequestPartitionId.defaultPartition();
|
||||
}
|
||||
|
||||
public ResourceModifiedMessage(FhirContext theFhirContext, IBaseResource theNewResource, OperationTypeEnum theOperationType, RequestDetails theRequest, RequestPartitionId theRequestPartitionId) {
|
||||
super(theFhirContext, theNewResource, theOperationType, theRequest);
|
||||
myPartitionId = theRequestPartitionId;
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,6 +76,14 @@ public class ResourceModifiedMessage extends BaseResourceModifiedMessage {
|
|||
mySubscriptionId = theSubscriptionId;
|
||||
}
|
||||
|
||||
public RequestPartitionId getPartitionId() {
|
||||
return myPartitionId;
|
||||
}
|
||||
|
||||
public void setPartitionId(RequestPartitionId thePartitionId) {
|
||||
myPartitionId = thePartitionId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -75,6 +91,7 @@ public class ResourceModifiedMessage extends BaseResourceModifiedMessage {
|
|||
.append("operationType", myOperationType)
|
||||
.append("subscriptionId", mySubscriptionId)
|
||||
.append("payloadId", myPayloadId)
|
||||
.append("partitionId", myPartitionId)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-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>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -58,37 +58,37 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r5</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<name>HAPI-FHIR</name>
|
||||
<description>An open-source implementation of the FHIR specification in Java.</description>
|
||||
<url>https://hapifhir.io</url>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>5.7.0-PRE6-SNAPSHOT</version>
|
||||
<version>5.7.0-PRE7-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
Loading…
Reference in New Issue