Skip to content

Commit 0a79f4e

Browse files
authored
6700 alternate api (hapifhir#6702)
* Make the Canonicalizer non-null-default-partition-id aware * Rename test * Changelog * Rework * Remove dead IT * remove fixme
1 parent d503a24 commit 0a79f4e

File tree

8 files changed

+122
-3
lines changed

8 files changed

+122
-3
lines changed

hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/model/RequestPartitionId.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,11 +333,13 @@ public static RequestPartitionId allPartitions() {
333333
}
334334

335335
@Nonnull
336+
// TODO GGG: This is a now-bad usage and we should remove it. we cannot assume null means default.
336337
public static RequestPartitionId defaultPartition() {
337338
return fromPartitionIds(Collections.singletonList(null));
338339
}
339340

340341
@Nonnull
342+
// TODO GGG: This is a now-bad usage and we should remove it. we cannot assume null means default.
341343
public static RequestPartitionId defaultPartition(@Nullable LocalDate thePartitionDate) {
342344
return fromPartitionIds(Collections.singletonList(null), thePartitionDate);
343345
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
type: fix
3+
issue: 6700
4+
title: "Previously if a non-null default partition ID was selected when partitioning is enabled, the subscription matcher would fail to find cross-partition subscriptions, causing subscriptions to appear to not be working. This has been corrected."

hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/SubscriptionRegisteringSubscriberTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
55
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
66
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
7-
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
87
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
98
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
109
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;

hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionCanonicalizerTest.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
package ca.uhn.fhir.jpa.subscription.match.registry;
22

33
import ca.uhn.fhir.context.FhirContext;
4+
import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
45
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
56
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
7+
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
68
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
79
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
810
import ca.uhn.fhir.jpa.subscription.model.CanonicalTopicSubscriptionFilter;
911
import ca.uhn.fhir.model.api.ExtensionDt;
1012
import ca.uhn.fhir.model.primitive.BooleanDt;
13+
import ca.uhn.fhir.rest.api.Constants;
14+
import ca.uhn.fhir.rest.api.server.RequestDetails;
1115
import ca.uhn.fhir.subscription.SubscriptionConstants;
1216
import ca.uhn.fhir.subscription.SubscriptionTestDataHelper;
1317
import ca.uhn.fhir.util.HapiExtensions;
1418
import jakarta.annotation.Nonnull;
1519
import org.assertj.core.api.AssertionsForClassTypes;
20+
import org.hl7.fhir.instance.model.api.IBaseResource;
1621
import org.hl7.fhir.r4.model.BooleanType;
1722
import org.hl7.fhir.r4.model.Extension;
1823
import org.hl7.fhir.r4.model.Subscription;
1924
import org.hl7.fhir.r5.model.Coding;
2025
import org.hl7.fhir.r5.model.Enumerations;
26+
import org.jetbrains.annotations.NotNull;
27+
import org.jetbrains.annotations.Nullable;
2128
import org.junit.jupiter.api.Test;
2229
import org.junit.jupiter.params.ParameterizedTest;
2330
import org.junit.jupiter.params.provider.MethodSource;
2431
import org.junit.jupiter.params.provider.ValueSource;
2532

33+
import java.util.Set;
2634
import java.util.stream.Stream;
2735

2836
import static ca.uhn.fhir.rest.api.Constants.CT_FHIR_JSON_NEW;
@@ -37,6 +45,8 @@
3745

3846
class SubscriptionCanonicalizerTest {
3947

48+
private static final Integer NON_NULL_DEFAULT_PARTITION_ID = 666;
49+
4050
FhirContext r4Context = FhirContext.forR4();
4151

4252
private final SubscriptionCanonicalizer testedSC = new SubscriptionCanonicalizer(r4Context, new SubscriptionSettings());
@@ -172,6 +182,90 @@ private static Stream<RequestPartitionId> crossPartitionParams() {
172182
return Stream.of(null, RequestPartitionId.fromPartitionId(1), RequestPartitionId.defaultPartition()) ;
173183
}
174184

185+
private class FakeNonNullDefaultPartitionIDHelper implements IRequestPartitionHelperSvc {
186+
187+
@Override
188+
public @Nullable Integer getDefaultPartitionId() {
189+
return NON_NULL_DEFAULT_PARTITION_ID;
190+
}
191+
192+
@Override
193+
public boolean isDefaultPartition(@NotNull RequestPartitionId theRequestPartitionId) {
194+
return theRequestPartitionId.getPartitionIds().get(0).equals(NON_NULL_DEFAULT_PARTITION_ID);
195+
}
196+
197+
@Override
198+
public boolean hasDefaultPartitionId(@NotNull RequestPartitionId theRequestPartitionId) {
199+
return theRequestPartitionId.getPartitionIds().stream().anyMatch(part -> part.equals(NON_NULL_DEFAULT_PARTITION_ID));
200+
}
201+
202+
@Override
203+
public RequestPartitionId determineReadPartitionForRequest(@Nullable RequestDetails theRequest, @NotNull ReadPartitionIdRequestDetails theDetails) {
204+
return null;
205+
}
206+
207+
@Override
208+
public RequestPartitionId determineGenericPartitionForRequest(RequestDetails theRequestDetails) {
209+
return null;
210+
}
211+
212+
@Override
213+
public @NotNull RequestPartitionId determineCreatePartitionForRequest(@Nullable RequestDetails theRequest, @NotNull IBaseResource theResource, @NotNull String theResourceType) {
214+
return null;
215+
}
216+
217+
@Override
218+
public @NotNull Set<Integer> toReadPartitions(@NotNull RequestPartitionId theRequestPartitionId) {
219+
return Set.of();
220+
}
221+
222+
@Override
223+
public boolean isResourcePartitionable(String theResourceType) {
224+
return false;
225+
}
226+
227+
@Override
228+
public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) {
229+
return null;
230+
}
231+
232+
@Override
233+
public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) {
234+
return null;
235+
}
236+
}
237+
@Test
238+
public void testNonNullDefaultPartitionIDCanonicalizesToCrossPartition() {
239+
IRequestPartitionHelperSvc myHelperSvc = new FakeNonNullDefaultPartitionIDHelper();
240+
final SubscriptionSettings subscriptionSettings = new SubscriptionSettings();
241+
242+
subscriptionSettings.setCrossPartitionSubscriptionEnabled(true);
243+
final SubscriptionCanonicalizer subscriptionCanonicalizer = new SubscriptionCanonicalizer(FhirContext.forR4(), subscriptionSettings);
244+
subscriptionCanonicalizer.setPartitionHelperSvc(myHelperSvc);
245+
Subscription subscription = buildMdmSubscriptionR4("test-subscription", "Patient?");
246+
CanonicalSubscription canonicalize = subscriptionCanonicalizer.canonicalize(subscription);
247+
248+
assertThat(canonicalize.isCrossPartitionEnabled()).isTrue();
249+
250+
}
251+
private Subscription buildMdmSubscriptionR4(String theId, String theCriteria) {
252+
Subscription retval = new Subscription();
253+
retval.setId(theId);
254+
retval.setReason("MDM Simulacrum Subscription");
255+
retval.setStatus(Subscription.SubscriptionStatus.REQUESTED);
256+
retval.setCriteria(theCriteria);
257+
retval.addExtension()
258+
.setUrl(HapiExtensions.EXTENSION_SUBSCRIPTION_CROSS_PARTITION)
259+
.setValue(new BooleanType().setValue(true));
260+
Subscription.SubscriptionChannelComponent channel = retval.getChannel();
261+
channel.setType(Subscription.SubscriptionChannelType.MESSAGE);
262+
channel.setEndpoint("channel:test");
263+
channel.setPayload(Constants.CT_JSON);
264+
RequestPartitionId retPartId = RequestPartitionId.fromPartitionId(NON_NULL_DEFAULT_PARTITION_ID);
265+
retval.setUserData(Constants.RESOURCE_PARTITION_ID, retPartId);
266+
return retval;
267+
}
268+
175269
@ParameterizedTest
176270
@MethodSource("crossPartitionParams")
177271
void testSubscriptionCrossPartitionEnableProperty_forDstu2WithExtensionAndPartitions(RequestPartitionId theRequestPartitionId) {

hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionRegistryTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import ca.uhn.fhir.context.FhirContext;
44
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
5-
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
65
import ca.uhn.fhir.jpa.subscription.channel.subscription.ISubscriptionDeliveryChannelNamer;
76
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelRegistry;
87
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;

hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriberTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
77
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
88
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
9+
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
910
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionCriteriaParser;
1011
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionMatchDeliverer;
1112
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionMatchingSubscriber;
@@ -33,6 +34,7 @@
3334
import org.mockito.InjectMocks;
3435
import org.mockito.Mock;
3536
import org.mockito.Mockito;
37+
import org.springframework.beans.factory.annotation.Autowired;
3638

3739
import java.util.Collections;
3840
import java.util.List;
@@ -55,8 +57,12 @@
5557
public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscribableChannelDstu3Test {
5658
private final IFhirResourceDao<Subscription> myMockSubscriptionDao = Mockito.mock(IFhirResourceDao.class);
5759

60+
@Autowired
61+
private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
62+
5863
@BeforeEach
5964
public void beforeEach() {
65+
when(myRequestPartitionHelperSvc.isDefaultPartition(any(RequestPartitionId.class))).thenReturn(Boolean.TRUE);
6066
when(myMockSubscriptionDao.getResourceType()).thenReturn(Subscription.class);
6167
myDaoRegistry.register(myMockSubscriptionDao);
6268
}

hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/websocket/WebsocketConnectionValidatorTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
77
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
88
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
9+
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
910
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
1011
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryResourceMatcher;
1112
import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher;
@@ -66,6 +67,8 @@ public class WebsocketConnectionValidatorTest {
6667
@MockBean
6768
SubscriptionRegistry mySubscriptionRegistry;
6869
@MockBean
70+
IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
71+
@MockBean
6972
ISearchParamRegistry mySearchParamRegistry;
7073
@MockBean
7174
SubscriptionSettings mySubscriptionSettings;

hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionCanonicalizer.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import ca.uhn.fhir.i18n.Msg;
2525
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
2626
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
27+
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
2728
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
2829
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
2930
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
@@ -71,11 +72,20 @@ public class SubscriptionCanonicalizer {
7172
final FhirContext myFhirContext;
7273
private final SubscriptionSettings mySubscriptionSettings;
7374

75+
private IRequestPartitionHelperSvc myHelperSvc;
76+
7477
@Autowired
7578
public SubscriptionCanonicalizer(FhirContext theFhirContext, SubscriptionSettings theSubscriptionSettings) {
7679
myFhirContext = theFhirContext;
7780
mySubscriptionSettings = theSubscriptionSettings;
7881
}
82+
// TODO GGG: Eventually, we will unify autowiring styles. It is this way now as this is the least destrctive method
83+
// to accomplish a minimal MR. I recommend moving all dependencies to setter autowiring, but that is for another
84+
// day.
85+
@Autowired
86+
public void setPartitionHelperSvc(IRequestPartitionHelperSvc thePartitionHelperSvc) {
87+
myHelperSvc = thePartitionHelperSvc;
88+
}
7989

8090
// TODO: LD: remove this constructor once all callers call the 2 arg constructor above
8191

@@ -787,7 +797,9 @@ private boolean handleCrossPartition(IBaseResource theSubscription) {
787797
boolean isSubscriptionCreatedOnDefaultPartition = false;
788798

789799
if (nonNull(requestPartitionId)) {
790-
isSubscriptionCreatedOnDefaultPartition = requestPartitionId.isDefaultPartition();
800+
isSubscriptionCreatedOnDefaultPartition = myHelperSvc == null
801+
? requestPartitionId.isDefaultPartition()
802+
: myHelperSvc.isDefaultPartition(requestPartitionId);
791803
}
792804

793805
boolean isSubscriptionDefinededAsCrossPartitionSubscription =

0 commit comments

Comments
 (0)