35
35
import ca .uhn .fhir .rest .server .exceptions .UnprocessableEntityException ;
36
36
import ca .uhn .fhir .rest .server .servlet .ServletRequestDetails ;
37
37
import ca .uhn .fhir .rest .server .util .CompositeInterceptorBroadcaster ;
38
+ import ca .uhn .fhir .util .Logs ;
38
39
import jakarta .annotation .Nonnull ;
39
40
import jakarta .annotation .Nullable ;
40
41
import org .apache .commons .lang3 .StringUtils ;
41
42
import org .hl7 .fhir .instance .model .api .IBaseResource ;
43
+ import org .slf4j .Logger ;
42
44
import org .springframework .beans .factory .annotation .Autowired ;
43
45
44
46
import java .util .ArrayList ;
50
52
51
53
public abstract class BaseRequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
52
54
55
+ public static final Logger ourLog = Logs .getPartitionTroubleshootingLog ();
53
56
private final HashSet <Object > myNonPartitionableResourceNames ;
54
57
55
58
@ Autowired
@@ -61,7 +64,7 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
61
64
@ Autowired
62
65
PartitionSettings myPartitionSettings ;
63
66
64
- public BaseRequestPartitionHelperSvc () {
67
+ protected BaseRequestPartitionHelperSvc () {
65
68
myNonPartitionableResourceNames = new HashSet <>();
66
69
67
70
// Infrastructure
@@ -107,6 +110,7 @@ public RequestPartitionId determineReadPartitionForRequest(
107
110
// SystemRequestDetails instead.
108
111
if (requestDetails == null ) {
109
112
requestDetails = new SystemRequestDetails ();
113
+ logSubstitutingDefaultSystemRequestDetails ();
110
114
}
111
115
112
116
boolean nonPartitionableResource = isResourceNonPartitionable (resourceType );
@@ -117,33 +121,84 @@ public RequestPartitionId determineReadPartitionForRequest(
117
121
&& systemRequestHasExplicitPartition ((SystemRequestDetails ) requestDetails )
118
122
&& !nonPartitionableResource ) {
119
123
requestPartitionId = getSystemRequestPartitionId ((SystemRequestDetails ) requestDetails , false );
124
+ logSystemRequestDetailsResolution ((SystemRequestDetails ) requestDetails );
125
+
120
126
} else if ((requestDetails instanceof SystemRequestDetails ) && nonPartitionableResource ) {
121
127
requestPartitionId = RequestPartitionId .fromPartitionId (myPartitionSettings .getDefaultPartitionId ());
128
+ logSystemRequestDetailsResolution ((SystemRequestDetails ) requestDetails );
129
+ logNonPartitionableType (resourceType );
122
130
} else {
131
+ // TODO mb: why is this path different than create?
132
+ // Here, a non-partitionable resource is still delivered to the pointcuts.
123
133
IInterceptorBroadcaster compositeBroadcaster =
124
134
CompositeInterceptorBroadcaster .newCompositeBroadcaster (myInterceptorBroadcaster , requestDetails );
125
135
if (compositeBroadcaster .hasHooks (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY )) {
126
- // Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
127
- HookParams params = new HookParams ()
128
- .add (RequestDetails .class , requestDetails )
129
- .addIfMatchesType (ServletRequestDetails .class , requestDetails );
130
- requestPartitionId = (RequestPartitionId )
131
- compositeBroadcaster .callHooksAndReturnObject (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY , params );
136
+ requestPartitionId = callAnyPointcut (compositeBroadcaster , requestDetails );
132
137
} else if (compositeBroadcaster .hasHooks (Pointcut .STORAGE_PARTITION_IDENTIFY_READ )) {
133
- // Interceptor call: STORAGE_PARTITION_IDENTIFY_READ
134
- HookParams params = new HookParams ()
135
- .add (RequestDetails .class , requestDetails )
136
- .addIfMatchesType (ServletRequestDetails .class , requestDetails )
137
- .add (ReadPartitionIdRequestDetails .class , theDetails );
138
- requestPartitionId = (RequestPartitionId )
139
- compositeBroadcaster .callHooksAndReturnObject (Pointcut .STORAGE_PARTITION_IDENTIFY_READ , params );
138
+ requestPartitionId = callReadPointcut (compositeBroadcaster , requestDetails , theDetails );
140
139
}
141
140
}
142
141
143
142
validateRequestPartitionNotNull (
144
143
requestPartitionId , Pointcut .STORAGE_PARTITION_IDENTIFY_ANY , Pointcut .STORAGE_PARTITION_IDENTIFY_READ );
145
144
146
- return validateAndNormalizePartition (requestPartitionId , requestDetails , resourceType );
145
+ RequestPartitionId resultRequestPartitionId =
146
+ validateAndNormalizePartition (requestPartitionId , requestDetails , resourceType );
147
+ logTroubleshootingResult ("read" , resourceType , theRequest , resultRequestPartitionId );
148
+
149
+ return resultRequestPartitionId ;
150
+ }
151
+
152
+ private static RequestPartitionId callAnyPointcut (
153
+ IInterceptorBroadcaster compositeBroadcaster , RequestDetails requestDetails ) {
154
+ // Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
155
+ HookParams params = new HookParams ()
156
+ .add (RequestDetails .class , requestDetails )
157
+ .addIfMatchesType (ServletRequestDetails .class , requestDetails );
158
+
159
+ return callAndLog (compositeBroadcaster , Pointcut .STORAGE_PARTITION_IDENTIFY_ANY , params );
160
+ }
161
+
162
+ private static RequestPartitionId callCreatePointcut (
163
+ IInterceptorBroadcaster compositeBroadcaster ,
164
+ RequestDetails requestDetails ,
165
+ @ Nonnull IBaseResource theResource ) {
166
+ // Interceptor call: STORAGE_PARTITION_IDENTIFY_CREATE
167
+ HookParams params = new HookParams ()
168
+ .add (IBaseResource .class , theResource )
169
+ .add (RequestDetails .class , requestDetails )
170
+ .addIfMatchesType (ServletRequestDetails .class , requestDetails );
171
+
172
+ return callAndLog (compositeBroadcaster , Pointcut .STORAGE_PARTITION_IDENTIFY_CREATE , params );
173
+ }
174
+
175
+ private static RequestPartitionId callAndLog (
176
+ IInterceptorBroadcaster compositeBroadcaster , Pointcut pointcut , HookParams params ) {
177
+ RequestPartitionId result =
178
+ (RequestPartitionId ) compositeBroadcaster .callHooksAndReturnObject (pointcut , params );
179
+
180
+ if (ourLog .isTraceEnabled ()) {
181
+ ourLog .trace (
182
+ "{}: result={} hooks={}" , pointcut , result , compositeBroadcaster .getInvokersForPointcut (pointcut ));
183
+ }
184
+ return result ;
185
+ }
186
+
187
+ private static RequestPartitionId callReadPointcut (
188
+ IInterceptorBroadcaster compositeBroadcaster ,
189
+ RequestDetails requestDetails ,
190
+ @ Nonnull ReadPartitionIdRequestDetails theDetails ) {
191
+ // Interceptor call: STORAGE_PARTITION_IDENTIFY_READ
192
+ HookParams params = new HookParams ()
193
+ .add (RequestDetails .class , requestDetails )
194
+ .addIfMatchesType (ServletRequestDetails .class , requestDetails )
195
+ .add (ReadPartitionIdRequestDetails .class , theDetails );
196
+
197
+ return callAndLog (compositeBroadcaster , Pointcut .STORAGE_PARTITION_IDENTIFY_READ , params );
198
+ }
199
+
200
+ private static void logNonPartitionableType (String theResourceType ) {
201
+ ourLog .trace ("Partitioning: resource type {} must be on the DEFAULT partition." , theResourceType );
147
202
}
148
203
149
204
@ Override
@@ -157,16 +212,12 @@ public RequestPartitionId determineGenericPartitionForRequest(RequestDetails the
157
212
if (theRequestDetails instanceof SystemRequestDetails
158
213
&& systemRequestHasExplicitPartition ((SystemRequestDetails ) theRequestDetails )) {
159
214
requestPartitionId = getSystemRequestPartitionId ((SystemRequestDetails ) theRequestDetails );
215
+ logSystemRequestDetailsResolution ((SystemRequestDetails ) theRequestDetails );
160
216
} else {
161
217
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster .newCompositeBroadcaster (
162
218
myInterceptorBroadcaster , theRequestDetails );
163
219
if (compositeBroadcaster .hasHooks (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY )) {
164
- // Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
165
- HookParams params = new HookParams ()
166
- .add (RequestDetails .class , theRequestDetails )
167
- .addIfMatchesType (ServletRequestDetails .class , theRequestDetails );
168
- requestPartitionId = (RequestPartitionId )
169
- compositeBroadcaster .callHooksAndReturnObject (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY , params );
220
+ requestPartitionId = callAnyPointcut (compositeBroadcaster , theRequestDetails );
170
221
}
171
222
}
172
223
@@ -175,10 +226,13 @@ && systemRequestHasExplicitPartition((SystemRequestDetails) theRequestDetails))
175
226
// validateRequestPartitionNotNull(requestPartitionId, Pointcut.STORAGE_PARTITION_IDENTIFY_ANY);
176
227
177
228
if (requestPartitionId != null ) {
178
- return validateAndNormalizePartition (
229
+ requestPartitionId = validateAndNormalizePartition (
179
230
requestPartitionId , theRequestDetails , theRequestDetails .getResourceName ());
180
231
}
181
- return null ;
232
+
233
+ logTroubleshootingResult ("generic" , theRequestDetails .getResourceName (), theRequestDetails , requestPartitionId );
234
+
235
+ return requestPartitionId ;
182
236
}
183
237
184
238
/**
@@ -240,37 +294,30 @@ public RequestPartitionId determineCreatePartitionForRequest(
240
294
// SystemRequestDetails instead.
241
295
if (theRequest == null ) {
242
296
requestDetails = new SystemRequestDetails ();
297
+ logSubstitutingDefaultSystemRequestDetails ();
243
298
}
244
299
245
300
RequestPartitionId requestPartitionId = null ;
246
301
if (theRequest instanceof SystemRequestDetails
247
302
&& systemRequestHasExplicitPartition ((SystemRequestDetails ) theRequest )) {
248
303
requestPartitionId =
249
304
getSystemRequestPartitionId ((SystemRequestDetails ) theRequest , nonPartitionableResource );
305
+
306
+ logSystemRequestDetailsResolution ((SystemRequestDetails ) theRequest );
250
307
} else {
251
308
IInterceptorBroadcaster compositeBroadcaster =
252
309
CompositeInterceptorBroadcaster .newCompositeBroadcaster (myInterceptorBroadcaster , requestDetails );
253
310
if (compositeBroadcaster .hasHooks (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY )) {
254
- // Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
255
- HookParams params = new HookParams ()
256
- .add (RequestDetails .class , requestDetails )
257
- .addIfMatchesType (ServletRequestDetails .class , requestDetails );
258
- requestPartitionId = (RequestPartitionId )
259
- compositeBroadcaster .callHooksAndReturnObject (Pointcut .STORAGE_PARTITION_IDENTIFY_ANY , params );
311
+ requestPartitionId = callAnyPointcut (compositeBroadcaster , requestDetails );
260
312
} else if (compositeBroadcaster .hasHooks (Pointcut .STORAGE_PARTITION_IDENTIFY_CREATE )) {
261
- // Interceptor call: STORAGE_PARTITION_IDENTIFY_CREATE
262
- HookParams params = new HookParams ()
263
- .add (IBaseResource .class , theResource )
264
- .add (RequestDetails .class , requestDetails )
265
- .addIfMatchesType (ServletRequestDetails .class , requestDetails );
266
- requestPartitionId = (RequestPartitionId ) compositeBroadcaster .callHooksAndReturnObject (
267
- Pointcut .STORAGE_PARTITION_IDENTIFY_CREATE , params );
313
+ requestPartitionId = callCreatePointcut (compositeBroadcaster , requestDetails , theResource );
268
314
}
269
315
}
270
316
271
317
// If the interceptors haven't selected a partition, and its a non-partitionable resource anyhow, send
272
318
// to DEFAULT
273
319
if (nonPartitionableResource && requestPartitionId == null ) {
320
+ logNonPartitionableType (theResourceType );
274
321
requestPartitionId = RequestPartitionId .defaultPartition ();
275
322
}
276
323
@@ -280,7 +327,12 @@ && systemRequestHasExplicitPartition((SystemRequestDetails) theRequest)) {
280
327
Pointcut .STORAGE_PARTITION_IDENTIFY_ANY );
281
328
validatePartitionForCreate (requestPartitionId , theResourceType );
282
329
283
- return validateAndNormalizePartition (requestPartitionId , requestDetails , theResourceType );
330
+ RequestPartitionId resultRequestPartitionId =
331
+ validateAndNormalizePartition (requestPartitionId , requestDetails , theResourceType );
332
+
333
+ logTroubleshootingResult ("create" , theResourceType , theRequest , resultRequestPartitionId );
334
+
335
+ return resultRequestPartitionId ;
284
336
}
285
337
286
338
private boolean systemRequestHasExplicitPartition (@ Nonnull SystemRequestDetails theRequest ) {
@@ -336,6 +388,8 @@ && hasDefaultPartitionId(retVal)) {
336
388
retVal = RequestPartitionId .fromPartitionIds (partitionIds );
337
389
}
338
390
391
+ ourLog .trace ("Partition normalization: {} -> {}" , theRequestPartitionId , retVal );
392
+
339
393
return retVal ;
340
394
}
341
395
@@ -418,4 +472,28 @@ private static void validateSinglePartitionIdOrName(@Nullable List<?> thePartiti
418
472
+ thePartitionIds );
419
473
}
420
474
}
475
+
476
+ private static void logTroubleshootingResult (
477
+ String theAction ,
478
+ String theResourceType ,
479
+ @ Nullable RequestDetails theRequest ,
480
+ RequestPartitionId theResult ) {
481
+ String tenantId = theRequest != null ? theRequest .getTenantId () : null ;
482
+ ourLog .debug (
483
+ "Partitioning: action={} resource type={} with request tenant ID={} routed to RequestPartitionId={}" ,
484
+ theAction ,
485
+ theResourceType ,
486
+ tenantId ,
487
+ theResult );
488
+ }
489
+
490
+ private void logSystemRequestDetailsResolution (SystemRequestDetails theRequest ) {
491
+ ourLog .trace (
492
+ "Partitioning: request is a SystemRequestDetails, with RequestPartitionId={}." ,
493
+ theRequest .getRequestPartitionId ());
494
+ }
495
+
496
+ private static void logSubstitutingDefaultSystemRequestDetails () {
497
+ ourLog .trace ("No RequestDetails present. Using default SystemRequestDetails." );
498
+ }
421
499
}
0 commit comments