001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2025 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.fhir.interceptor;
011
012import ca.cdr.api.consent.ConsentLookupContext;
013import ca.cdr.api.fhirgw.json.AvailableRoutesJson;
014import ca.cdr.api.fhirgw.json.GatewayTargetJson;
015import ca.cdr.api.fhirgw.json.MatchedRoutesJson;
016import ca.cdr.api.fhirgw.model.CreateRequest;
017import ca.cdr.api.fhirgw.model.DeleteRequest;
018import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
019import ca.cdr.api.fhirgw.model.OperationRequest;
020import ca.cdr.api.fhirgw.model.OperationResponse;
021import ca.cdr.api.fhirgw.model.ReadRequest;
022import ca.cdr.api.fhirgw.model.SearchPageRequest;
023import ca.cdr.api.fhirgw.model.SearchRequest;
024import ca.cdr.api.fhirgw.model.SearchResponse;
025import ca.cdr.api.fhirgw.model.TransactionRequest;
026import ca.cdr.api.fhirgw.model.UpdateRequest;
027import ca.cdr.api.model.json.ConvertedTransactionBundlesJson;
028import ca.cdr.api.model.json.IOAuth2ClientDetails;
029import ca.cdr.api.model.json.UserSessionDetailsJson;
030import ca.cdr.api.model.json.appgallery.common.AGApplicationJson;
031import ca.cdr.api.model.json.appgallery.console.AGConsoleJson;
032import ca.cdr.api.persistence.megascale.MegaScaleCredentialRequestJson;
033import ca.cdr.api.persistence.megascale.MegaScaleCredentialResponseJson;
034import ca.cdr.api.priorauth.PriorAuthCrdContextJson;
035import ca.cdr.api.pub.cdaexchange.model.CdaToFhirConversionResultJson;
036import ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson;
037import ca.uhn.fhir.interceptor.api.IPointcut;
038import ca.uhn.fhir.rest.api.server.RequestDetails;
039import ca.uhn.fhir.rest.api.server.cdshooks.CdsServiceRequestJson;
040import ca.uhn.fhir.rest.server.interceptor.consent.IConsentService;
041import ca.uhn.fhir.rest.server.messaging.json.ResourceOperationJsonMessage;
042import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
043import ca.uhn.hl7v2.model.Message;
044import jakarta.annotation.Nonnull;
045import org.apache.commons.lang3.ArrayUtils;
046import org.hl7.fhir.instance.model.api.IBaseBundle;
047import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
048import org.hl7.fhir.instance.model.api.IBaseResource;
049
050import java.security.KeyStore;
051import java.util.Arrays;
052import java.util.Collections;
053import java.util.HashSet;
054import java.util.List;
055import java.util.Set;
056import java.util.stream.Collectors;
057
058/**
059 * Value for {@link CdrHook#value()}
060 * <p>
061 * Hook pointcuts are divided into several broad categories:
062 * <ul>
063 * <li>FHIRGW_xxx: Hooks on the FHIR Gateway module</li>
064 * </ul>
065 * </p>
066 */
067public enum CdrPointcut implements IPointcut {
068
069        /**
070         * <b>CDA pre-import Hook:</b>
071         * <p>This pointcut provides access to documents before they are imported via the $import-cda endpoint.</p>
072         * <p>Hooks may accept the following parameters:</p>
073         * <ul>
074         *    <li>{@link java.lang.String} - the document to be imported, in xml format.</li>
075         *    <li>{@link ca.cdr.api.pub.cdaexchange.model.CdaToFhirConversionResultJson} - object used to contain all
076         *    relevant data involved in the conversion of a CDA document to an IBaseBundle.</li>
077         * </ul>
078         * <p>Hooks should return the document after performing any modifications.</p>
079         */
080        CDA_PRE_IMPORT(String.class, String.class, CdaToFhirConversionResultJson.class),
081
082        /**
083         * <b>CDA post-import Hook:</b>
084         * <p>This pointcut provides access to documents after they are imported via the $import-cda endpoint.</p>
085         * <p>Hooks may accept the following parameters:</p>
086         * <ul>
087         *    <li>{@link IBaseOperationOutcome} - an operation outcome which can be used to track issues with the import.</li>
088         *    <li>{@link IBaseBundle} - the transaction bundle which can be modified by this Hook.</li>
089         *    <li>{@link java.lang.String} - the document that was imported, in xml format.</li>
090         *    <li>{@link ca.cdr.api.pub.cdaexchange.model.CdaToFhirConversionResultJson} - object used to contain all
091         *    relevant data involved in the conversion of a CDA document to an IBaseBundle.</li>
092         * </ul>
093         * <p>To modify the document before the {@link IBaseBundle} is generated, use the pre-import Hook instead.</p>
094         */
095        CDA_POST_IMPORT(
096                        void.class,
097                        IBaseOperationOutcome.class,
098                        IBaseBundle.class,
099                        String.class,
100                        CdaToFhirConversionResultJson.class),
101
102        /**
103         * <b>CDA post-export Hook:</b>
104         * <p>This pointcut provides access to documents after they are exported, and immediately
105         * before they are returned to the API client.</p>
106         * <p>Hooks may accept the following parameters:</p>
107         * <ul>
108         *    <li>{@link IBaseBundle} - the bundle associated with this export.</li>
109         *    <li>{@link java.lang.String} - the document being exported, in xml format.</li>
110         * </ul>
111         * <p>Hooks should return the document after performing any modifications. The resulting document
112         * is what will be returned to the API client.</p>
113         */
114        CDA_POST_EXPORT(String.class, IBaseBundle.class, String.class),
115
116        /**
117         * <b>Channel Import Hook:</b>
118         * The pointcut provides access to messages received on a broker queue.  It allows an interceptor to
119         * inspect, modify or mark for discard incoming messages before ingestion by the Channel Import module.
120         * <p>
121         * <p>
122         * Hooks may accept the following parameters:
123         * <ul>
124         * <li>
125         * {@link ResourceOperationJsonMessage} - Hook methods for this
126         * pointcut should take a single parameter of ResourceOperationJsonMessage as the input. This object
127         * contains the pre-processed channel import message.
128         * </li>
129         * </ul>
130         *
131         * </p>
132         * Hook methods must return a <code>Boolean</code> which indicates whether to process the message.
133         */
134        CHANNEL_IMPORT_MESSAGE_PRE_PROCESSED(Boolean.class, ResourceOperationJsonMessage.class),
135
136        /**
137         * <b>FHIR Gateway Hook:</b>
138         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
139         * a given FHIR <b>delete</b> operation. This hook is called once per client request, regardless of how many individual
140         * targets are eventually invoked against.
141         * <p>
142         * Hooks may accept the following parameters:
143         * <ul>
144         * <li>
145         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
146         * is about to be processed.
147         * </li>
148         * <li>
149         * {@link ca.cdr.api.fhirgw.model.DeleteRequest} - The delete that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
150         * </li>
151         * <li>
152         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
153         * </li>
154         * <li>
155         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
156         * </li>
157         * </ul>
158         * </p>
159         * Hook methods must return <code>void</code>.
160         *
161         */
162        FHIRGW_DELETE_POST_SELECT_ROUTE(
163                        void.class,
164                        ServletRequestDetails.class,
165                        DeleteRequest.class,
166                        MatchedRoutesJson.class,
167                        AvailableRoutesJson.class),
168
169        /**
170         * <b>FHIR Gateway Hook:</b>
171         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
172         * a given FHIR <b>update</b> operation. This hook is called once per client request, regardless of how many individual
173         * targets are eventually invoked against.
174         * <p>
175         * Hooks may accept the following parameters:
176         * <ul>
177         * <li>
178         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
179         * is about to be processed.
180         * </li>
181         * <li>
182         * {@link ca.cdr.api.fhirgw.model.UpdateRequest} - The update that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
183         * </li>
184         * <li>
185         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
186         * </li>
187         * <li>
188         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
189         * </li>
190         * </ul>
191         * </p>
192         * Hook methods must return <code>void</code>.
193         *
194         */
195        FHIRGW_UPDATE_POST_SELECT_ROUTE(
196                        void.class,
197                        ServletRequestDetails.class,
198                        UpdateRequest.class,
199                        MatchedRoutesJson.class,
200                        AvailableRoutesJson.class),
201
202        /**
203         * <b>FHIR Gateway Hook:</b>
204         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
205         * a given FHIR <b>operation</b> operation. This hook is called once per client request, regardless of how many individual
206         * targets are eventually invoked against.
207         * <p>
208         * Hooks may accept the following parameters:
209         * <ul>
210         * <li>
211         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
212         * is about to be processed.
213         * </li>
214         * <li>
215         * {@link ca.cdr.api.fhirgw.model.OperationRequest} - The operation that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
216         * </li>
217         * <li>
218         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
219         * </li>
220         * <li>
221         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
222         * </li>
223         * </ul>
224         * </p>
225         * Hook methods must return <code>void</code>.
226         *
227         */
228        FHIRGW_OPERATION_POST_SELECT_ROUTE(
229                        void.class,
230                        ServletRequestDetails.class,
231                        OperationRequest.class,
232                        MatchedRoutesJson.class,
233                        AvailableRoutesJson.class),
234
235        /**
236         * <b>FHIR Gateway Hook:</b>
237         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
238         * a given FHIR <b>search</b> operation. This hook is called once per client request, regardless of how many individual
239         * targets are eventually invoked against.
240         * <p>
241         * Hooks may accept the following parameters:
242         * <ul>
243         * <li>
244         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
245         * is about to be processed.
246         * </li>
247         * <li>
248         * {@link ca.cdr.api.fhirgw.model.SearchRequest} - The search that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
249         * </li>
250         * <li>
251         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
252         * </li>
253         * <li>
254         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
255         * </li>
256         * </ul>
257         * </p>
258         * Hook methods must return <code>void</code>.
259         *
260         */
261        FHIRGW_SEARCH_POST_SELECT_ROUTE(
262                        void.class,
263                        ServletRequestDetails.class,
264                        SearchRequest.class,
265                        MatchedRoutesJson.class,
266                        AvailableRoutesJson.class),
267
268        /**
269         * <b>FHIR Gateway Hook:</b>
270         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
271         * a given FHIR <b>create</b> operation. This hook is called once per client request, regardless of how many individual
272         * targets are eventually invoked against.
273         * <p>
274         * Hooks may accept the following parameters:
275         * <ul>
276         * <li>
277         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
278         * is about to be processed.
279         * </li>
280         * <li>
281         * {@link ca.cdr.api.fhirgw.model.CreateRequest} - The create that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
282         * </li>
283         * <li>
284         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
285         * </li>
286         * <li>
287         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
288         * </li>
289         * </ul>
290         * </p>
291         * Hook methods must return <code>void</code>.
292         *
293         */
294        FHIRGW_CREATE_POST_SELECT_ROUTE(
295                        void.class,
296                        ServletRequestDetails.class,
297                        CreateRequest.class,
298                        MatchedRoutesJson.class,
299                        AvailableRoutesJson.class),
300
301        /**
302         * <b>FHIR Gateway Hook:</b>
303         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
304         * a given FHIR <b>read</b> operation. This hook is called once per client request, regardless of how many individual
305         * targets are eventually invoked against.
306         * <p>
307         * Hooks may accept the following parameters:
308         * <ul>
309         * <li>
310         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
311         * is about to be processed.
312         * </li>
313         * <li>
314         * {@link ca.cdr.api.fhirgw.model.ReadRequest} - The read that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers
315         * </li>
316         * <li>
317         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
318         * </li>
319         * <li>
320         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
321         * </li>
322         * </ul>
323         * </p>
324         * Hook methods must return <code>void</code>.
325         *
326         */
327        FHIRGW_READ_POST_SELECT_ROUTE(
328                        void.class,
329                        ServletRequestDetails.class,
330                        ReadRequest.class,
331                        MatchedRoutesJson.class,
332                        AvailableRoutesJson.class),
333
334        /**
335         * <b>FHIR Gateway Hook:</b>
336         * This hook is called when the FHIR Gateway has just determined which routes should be invoked for
337         * a given FHIR <b>transaction</b> operation. This hook is called once per client request, regardless of how many individual
338         * targets are eventually invoked against.
339         * <p>
340         * Hooks may accept the following parameters:
341         * <ul>
342         * <li>
343         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
344         * is about to be processed.
345         * </li>
346         * <li>
347         * {@link ca.cdr.api.fhirgw.model.TransactionRequest} - The transaction that is about to be invoked. The hook method can modify this request, and modifications will affect all the operations that are performed against the target servers.
348         * </li>
349         * <li>
350         * {@link ca.cdr.api.fhirgw.json.MatchedRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which have been selected for this request. Routes can be added or removed from this collection to affect which routes are invoked. They can be cast to their specific subclasses if necessary.
351         * </li>
352         * <li>
353         * {@link ca.cdr.api.fhirgw.json.AvailableRoutesJson} - A collection of {@link ca.cdr.api.fhirgw.json.IBaseRouteJson} which match the operation type of the request, e.g. read, create, delete, search, operation.
354         * </li>
355         * </ul>
356         * </p>
357         * Hook methods must return <code>void</code>.
358         *
359         */
360        FHIRGW_TRANSACTION_POST_SELECT_ROUTE(
361                        void.class,
362                        ServletRequestDetails.class,
363                        TransactionRequest.class,
364                        MatchedRoutesJson.class,
365                        AvailableRoutesJson.class),
366
367        /**
368         * <b>FHIR Gateway Hook:</b>
369         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>read</b> or <b>vread</b> operation against an individual
370         * target server. This hook is called once for each target that will be called, so if a single client read is being
371         * multicasted against two target servers, this hook will be invoked twice.
372         * <p>
373         * Hooks may accept the following parameters:
374         * <ul>
375         * <li>
376         * {@link ca.cdr.api.fhirgw.model.ReadRequest} - The read that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
377         * </li>
378         * <li>
379         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
380         * </li>
381         * <li>
382         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
383         * is about to be processed.
384         * </li>
385         * </ul>
386         * </p>
387         * Hook methods must return <code>void</code>.
388         */
389        FHIRGW_READ_TARGET_PREINVOKE(void.class, ReadRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
390
391        /**
392         * <b>FHIR Gateway Hook:</b>
393         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>operation</b> operation against an individual
394         * target server.
395         * <p>
396         * Hooks may accept the following parameters:
397         * <ul>
398         * <li>
399         * {@link ca.cdr.api.fhirgw.model.OperationRequest} - The read that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
400         * </li>
401         * <li>
402         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
403         * </li>
404         * <li>
405         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
406         * is about to be processed.
407         * </li>
408         * </ul>
409         * </p>
410         * Hook methods must return <code>void</code>.
411         */
412        FHIRGW_OPERATION_TARGET_PREINVOKE(
413                        void.class, OperationRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
414
415        /**
416         * <b>FHIR Gateway Hook:</b>
417         * This hook is called when the FHIR Gateway has finished invoking a FHIR <b>extended operation</b> operation against an individual
418         * target server. This hook is called once for each target that has been called, so if a single client operation is being
419         * multicasted against two target servers, this hook will be invoked twice.
420         * <p>
421         * <p>
422         * Hooks may accept the following parameters:
423         * <ul>
424         * <li>
425         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
426         * </li>
427         * <li>
428         * {@link ISearchResultsAccumulator} - The accumulator being used to collect the search results so far. This may be empty in the case of operations
429         * which do not return search results. Some operations, such as <b>$everything</b>, will return search results, but others such as <b>$</b>
430         * Hook methods may use this object to inspect results received by other endpoints when searching in serial mode, and can
431         * modify the results as needed. Note that the {@link #FHIRGW_SEARCH_TARGET_POSTINVOKE} pointcut is invoked once for each gateway
432         * target, <b>before</b> the search results are added to the accumulator. Results from the current target are found in the
433         * {@link SearchResponse} object, and will be moved from that object into the accumulator after this pointcut is complete.
434         * </li>
435         * <li>
436         * {@link ca.cdr.api.fhirgw.model.OperationResponse} - This object contains the Operation Response from the individual Gateway Target that was called. Interceptors may modify this object in any way they want. This may be null if the operation returns a Bundle (check the SearchResultsAccumulator instead).
437         * </li>
438         * </ul>
439         * </p>
440         * Hook methods must return <code>void</code>.
441         *
442         **/
443        FHIRGW_OPERATION_TARGET_POSTINVOKE(
444                        void.class,
445                        OperationRequest.class,
446                        ISearchResultsAccumulator.class,
447                        OperationResponse.class,
448                        GatewayTargetJson.class,
449                        ServletRequestDetails.class),
450
451        /**
452         * <b>FHIR Gateway Hook:</b>
453         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>search</b> operation against an individual
454         * target server. This hook is called once for each target that will be called, so if a single client search is being
455         * multicasted against two target servers, this hook will be invoked twice.
456         * <p>
457         * This hook can be contrasted with {@link #FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE}:
458         * <ul>
459         *    <li>{@link #FHIRGW_SEARCH_TARGET_PREINVOKE} is called before the initial search is performed (which should return search results as well as paging links)</li>
460         *    <li>{@link #FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE} is called before the subsequent pages of results are fetched</li>
461         * </ul>
462         * </p>
463         * <p>
464         * Hooks may accept the following parameters:
465         * <ul>
466         * <li>
467         * {@link ca.cdr.api.fhirgw.model.SearchRequest} - The search that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
468         * </li>
469         * <li>
470         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
471         * </li>
472         * <li>
473         * {@link ISearchResultsAccumulator} - The accumulator being used to collect the search results so far. Hook methods may use this object to inspect results recieved by other endpoints when searching in serial mode, and can modify the results as needed.
474         * </li>
475         * <li>
476         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
477         * is about to be processed.
478         * </li>
479         * </ul>
480         * </p>
481         * Hook methods must return <code>void</code>.
482         */
483        FHIRGW_SEARCH_TARGET_PREINVOKE(
484                        void.class,
485                        SearchRequest.class,
486                        GatewayTargetJson.class,
487                        ISearchResultsAccumulator.class,
488                        ServletRequestDetails.class),
489
490        /**
491         * <b>FHIR Gateway Hook:</b>
492         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>search</b> paging operation against an individual
493         * target server. This hook is called once for each target that will be called, so if a single client search is being
494         * multicasted against two target servers, this hook will be invoked twice.
495         * <p>
496         * This hook can be contrasted with {@link #FHIRGW_SEARCH_TARGET_PREINVOKE}:
497         * <ul>
498         *    <li>{@link #FHIRGW_SEARCH_TARGET_PREINVOKE} is called before the initial search is performed (which should return search results as well as paging links)</li>
499         *    <li>{@link #FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE} is called before the subsequent pages of results are fetched</li>
500         * </ul>
501         * </p>
502         * <p>
503         * Hooks may accept the following parameters:
504         * <ul>
505         * <li>
506         * {@link ca.cdr.api.fhirgw.model.SearchPageRequest} - The search that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
507         * </li>
508         * <li>
509         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
510         * </li>
511         * <li>
512         * {@link ISearchResultsAccumulator} - The accumulator being used to collect the search results so far. Hook methods may use this object to inspect results received by other endpoints when searching in serial mode, and can modify the results as needed.
513         * </li>
514         * <li>
515         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
516         * is about to be processed.
517         * </li>
518         * </ul>
519         * </p>
520         * Hook methods must return <code>void</code>.
521         */
522        FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE(
523                        void.class,
524                        SearchPageRequest.class,
525                        GatewayTargetJson.class,
526                        ISearchResultsAccumulator.class,
527                        ServletRequestDetails.class),
528
529        /**
530         * <b>FHIR Gateway Hook:</b>
531         * This hook is called when the FHIR Gateway has finished invoking a FHIR <b>search</b> operation against an individual
532         * target server. This hook is called once for each target that has been called, so if a single client search is being
533         * multicasted against two target servers, this hook will be invoked twice.
534         * <p>
535         * <p>
536         * Hooks may accept the following parameters:
537         * <ul>
538         * <li>
539         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
540         * </li>
541         * <li>
542         * {@link ISearchResultsAccumulator} - The accumulator being used to collect the search results so far.
543         * Hook methods may use this object to inspect results received by other endpoints when searching in serial mode, and can
544         * modify the results as needed. Note that the {@link #FHIRGW_SEARCH_TARGET_POSTINVOKE} pointcut is invoked once for each gateway
545         * target, <b>before</b> the search results are added to the accumulator. Results from the current target are found in the
546         * {@link SearchResponse} object, and will be moved from that object into the accumulator after this pointcut is complete.
547         * </li>
548         * <li>
549         * {@link ca.cdr.api.fhirgw.model.SearchResponse} - This object contains the search results from the individual Gateway Target that was called. Interceptors may modify this object in any way they want.
550         * </li>
551         * </ul>
552         * </p>
553         * Hook methods must return <code>void</code>.
554         */
555        FHIRGW_SEARCH_TARGET_POSTINVOKE(
556                        void.class,
557                        GatewayTargetJson.class,
558                        ISearchResultsAccumulator.class,
559                        SearchResponse.class,
560                        ServletRequestDetails.class),
561
562        /**
563         * <b>FHIR Gateway Hook:</b>
564         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>create</b> operation against an individual
565         * target server. This hook is called once for each target that will be called, so if a single client create is being
566         * multicasted against two target servers, this hook will be invoked twice.
567         * <p>
568         * For creates where a client id is specified, the <b>update</b> hook will be fired instead.
569         * </p>
570         * <p>
571         * Hooks may accept the following parameters:
572         * <ul>
573         * <li>
574         * {@link ca.cdr.api.fhirgw.model.CreateRequest} - The create that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
575         * </li>
576         * <li>
577         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
578         * </li>
579         * <li>
580         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
581         * is about to be processed.
582         * </li>
583         * </ul>
584         * </p>
585         * Hook methods must return <code>void</code>.
586         */
587        FHIRGW_CREATE_TARGET_PREINVOKE(
588                        void.class, CreateRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
589
590        /**
591         * <b>FHIR Gateway Hook:</b>
592         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>transaction</b> operation against an individual
593         * target server. This hook is called once for each target that will be called, so if a single client create is being
594         * multicasted against two target servers, this hook will be invoked twice.
595         * <p>
596         * For creates where a client id is specified, the <b>update</b> hook will be fired instead.
597         * </p>
598         * <p>
599         * Hooks may accept the following parameters:
600         * <ul>
601         * <li>
602         * {@link ca.cdr.api.fhirgw.model.TransactionRequest} - The transaction that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
603         * </li>
604         * <li>
605         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
606         * </li>
607         * <li>
608         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
609         * is about to be processed.
610         * </li>
611         * </ul>
612         * </p>
613         * Hook methods must return <code>void</code>.
614         */
615        FHIRGW_TRANSACTION_TARGET_PREINVOKE(
616                        void.class, TransactionRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
617
618        /**
619         * <b>FHIR Gateway Hook:</b>
620         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>update</b> operation against an individual
621         * target server. This hook is called once for each target that will be called, so if a single client update is being
622         * multicasted against two target servers, this hook will be invoked twice.
623         * <p>
624         * This hook will also be called for <b>create</b> operations when a client id is provided.
625         * </p>
626         * <p>
627         * Hooks may accept the following parameters:
628         * <ul>
629         * <li>
630         * {@link ca.cdr.api.fhirgw.model.UpdateRequest} - The update that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
631         * </li>
632         * <li>
633         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
634         * </li>
635         * <li>
636         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
637         * is about to be processed.
638         * </li>
639         * </ul>
640         * </p>
641         * Hook methods must return <code>void</code>.
642         */
643        FHIRGW_UPDATE_TARGET_PREINVOKE(
644                        void.class, UpdateRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
645
646        /**
647         * <b>FHIR Gateway Hook:</b>
648         * This hook is called when the FHIR Gateway is about to invoke a FHIR <b>delete</b> operation against an individual
649         * target server. This hook is called once for each target that will be called, so if a single client delete is being
650         * multicasted against two target servers, this hook will be invoked twice.
651         * <p>
652         * Hooks may accept the following parameters:
653         * <ul>
654         * <li>
655         * {@link ca.cdr.api.fhirgw.model.DeleteRequest} - The delete that is about to be invoked. The hook method can modify this request, and modifications will affect the operation that is actually performed against the target server.
656         * </li>
657         * <li>
658         * {@link ca.cdr.api.fhirgw.json.GatewayTargetJson} - The gateway target server definition. Hook methods should not modify this object, and any changes will be ignored.
659         * </li>
660         * <li>
661         * {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails} - A bean containing details about the request that
662         * is about to be processed.
663         * </li>
664         * </ul>
665         * </p>
666         * Hook methods must return <code>void</code>.
667         */
668        FHIRGW_DELETE_TARGET_PREINVOKE(
669                        void.class, DeleteRequest.class, GatewayTargetJson.class, ServletRequestDetails.class),
670
671        /**
672         * <b>HL7v2 Hook:</b>
673         * This hook is the first one called when a HL7v2 endpoint processes incoming messages.  It is invoked before
674         * the HL7v2 to FHIR mapping takes place for each incoming request. It may be used to provide
675         * alternate handling for some requests, screen requests before they are handled, alter the incoming message,etc.
676         * <p>
677         * Note that any exceptions thrown by this method will not be trapped by HAPI (they will be passed up to the server)
678         * </p>
679         * <p>
680         * Hooks may accept the following parameters:
681         * <ul>
682         * <li>
683         * {@link ca.uhn.hl7v2.model.Message} - the message that is about to be processed. The hook method can modify this
684         * message and modifications will affect the end result of processing the message by this server.
685         * <br/>
686         * <b>NOTE:</b> This parameter is deprecated. Use {@link Hl7v2ToFhirConversionResultJson#getModifiableMessage()}
687         * or {@link Hl7v2ToFhirConversionResultJson#setModifiableMessage(Message)} instead.
688         * </li>
689         * <li>
690         * {@link Hl7v2ToFhirConversionResultJson} - Contains all relevant data involved in the conversion of an HL7 v2.x
691         * message to a list of IBaseBundle resources.
692         * </li>
693         * </ul>
694         * </p>
695         * Hook methods may return <code>true</code> or <code>void</code> if processing should continue normally.
696         * This is generally the right thing to do. If your interceptor is processing the response rather than
697         * letting HAPI do it, you must return <code>false</code>. In this case,
698         * no further processing will occur.
699         */
700        HL7V2IN_PRE_HL7V2_TO_FHIR_MAPPING_PROCESSING(
701                        Boolean.class, "ca.uhn.hl7v2.model.Message", "ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson"),
702
703        /**
704         * <b>HL7v2 Hook:</b>
705         * This hook is invoked after Smile has transformed an HL7V2 message into a collection of Transaction Bundle operations.
706         * <p>
707         * Note that any exceptions thrown by this method will not be trapped by HAPI (they will be passed up to the server)
708         * </p>
709         * <p>
710         * Hooks may accept the following parameters:
711         * <ul>
712         * <li>
713         * {@link ConvertedTransactionBundlesJson} - Contains a list of IBaseBundle objects, each of which represents a transaction about to be executed
714         * against the FHIR repository. Any modifications to this bundle, or additions to it, will be propagated into the repository.
715         * <br/>
716         * <b>NOTE:</b> This parameter is deprecated. Use {@link Hl7v2ToFhirConversionResultJson#getBundles()}
717         * or {@link Hl7v2ToFhirConversionResultJson#setBundles(List)} instead.
718         * </li>
719         * <li>
720         * {@link ca.uhn.hl7v2.model.Message} - the message that was just processed. Any changes to this message will be ignored,
721         * as it has already been processed.
722         * <br/>
723         * <b>NOTE:</b> This parameter is deprecated. Use {@link Hl7v2ToFhirConversionResultJson#getModifiableMessage()}
724         * or {@link Hl7v2ToFhirConversionResultJson#setModifiableMessage(Message)} instead.
725         * </li>
726         * <li>
727         * {@link Hl7v2ToFhirConversionResultJson} - Contains all relevant data involved in the conversion of an HL7 v2.x
728         * message to a list of IBaseBundle resources.
729         * </li>
730         * </ul>
731         * </p>
732         */
733        HL7V2IN_POST_HL7V2_TO_FHIR_MAPPING_PROCESSING(
734                        void.class,
735                        "ca.uhn.hl7v2.model.Message",
736                        "ca.cdr.api.model.json.ConvertedTransactionBundlesJson",
737                        "ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson"),
738
739        /**
740         * <b>Persistence (RDBMS) Hook:</b>
741         * This pointcut is invoked my the Persistence (RDBMS) module when
742         * running in MegaScale mode in order to request the database credentials
743         * associated with a given partition ID.
744         * <p>
745         * Hooks may accept the following parameters:
746         * <ul>
747         * <li>
748         * {@link MegaScaleCredentialRequestJson} - Hook methods for this
749         * pointcut should take a {@link MegaScaleCredentialRequestJson}
750         * as input. This object contains the numeric ID of the partition
751         * for which database credentials are wanted.
752         * </li>
753         * </ul>
754         * </p>
755         *
756         * Hook methods for this pointcut must return a
757         * {@link MegaScaleCredentialResponseJson} object which contains the
758         * JDBC URL and credentials associated with the partition ID. These
759         * credentials will be cached, so this Pointcut will not be invoked
760         * repeatedly for the same partition ID (therefore it is ok if hook
761         * methods have some latency).
762         *
763         * @since 2023.02.R01
764         */
765        STORAGE_MEGASCALE_PROVIDE_DB_INFO(MegaScaleCredentialResponseJson.class, MegaScaleCredentialRequestJson.class),
766
767        /**
768         * <b>Server Endpoint Hook:</b>
769         * The pointcut provides the capability to supply a provisioned KeyStore file for TLS base encryption.
770         * Note that pointcut {@link #SERVER_CONFIGURATION_KEYSTORE} is invoked only if the endpoint listener
771         * is said to required TLS encryption for incoming connections through environment property <b>tls.enabled</b>
772         * <p>
773         * <p>
774         * Hooks may accept the following parameters:
775         * <ul>
776         * <li>
777         * {@link java.lang.String} - The keystore password
778         * </li>
779         * </ul>
780         * </p>
781         * <p>
782         * Interceptors for this pointcut must be registered with the specific
783         * endpoint module where the keystore will be used.
784         * </p>
785         * Hook methods must return <code>KeyStore</code>.
786         */
787        SERVER_CONFIGURATION_KEYSTORE(KeyStore.class, String.class),
788
789        /**
790         * <b>SMART/OIDC Hook:</b>
791         * The pointcut is called when a SMART Outbound Security module is configured in
792         * federated mode, and there are multiple federated providers configured, prior to
793         * the user being asked to select a provider. This pointcut can be used to
794         * programmatically select a provider instead of relying on the user to
795         * make a selection.
796         * <p>
797         * Hooks may accept the following parameters:
798         * <ul>
799         * <li>
800         * {@literal ca.cdr.api.fhir.interceptor.OidcAuthRequestDetails} - This object contains details about the auth request and can be used to extract request parameter values.
801         * </li>
802         * </ul>
803         * </p>
804         * Hook methods may return a {@link String}, which should be the the Registration ID of an
805         * OpenID Connect Server definition (i.e. the value of the "Registration ID" field in the
806         * Smile CDR OIDC Server definition page). If the returned String is not {@literal null} and
807         * does not match any server definition, the flow will be halted and the user will
808         * see an error. If the returned string is {@literal null}, the user will be
809         * redirected to a server selection screen.
810         */
811        SMART_FEDERATED_OIDC_PRE_PROVIDER_SELECTION(String.class, OidcAuthRequestDetails.class),
812
813        /**
814         * <b>SMART/OIDC Hook:</b>
815         * The pointcut is called when an OIDC client is being saved. This could
816         * mean that a new client is being created, or an existing client
817         * is being updated or disabled.
818         * <p>
819         * This hook is called after the database transaction used to
820         * save the object has been committed. This means that the record already
821         * appears in the database. Any exceptions thrown by hooks for this
822         * pointcut may cause an error to appear for the user requesting the
823         * operation, but will not affect what has been saved in the database,
824         * so no exceptions should be thrown within this pointcut.
825         * </p>
826         * <p>
827         * Hooks may accept the following parameters:
828         * <ul>
829         * <li>
830         * {@link ca.cdr.api.model.json.IOAuth2ClientDetails} - The Client being saved. Pointcuts should not modify this object.
831         * </li>
832         * </ul>
833         * </p>
834         * Hook methods must return <code>void</code>.
835         */
836        SMART_OIDC_CLIENT_SAVED(void.class, IOAuth2ClientDetails.class),
837
838        /**
839         * <b>SMART/OIDC Hook:</b>
840         * The pointcut is called when an OIDC client is being saved. This could
841         * mean that a new client is being created, or an existing client
842         * is being updated or disabled.
843         * <p>
844         * This hook is called within the open database transaction used to
845         * save the object. This means that at the time this pointcut is invoked,
846         * the record does not yet appear in the database. It also means that any
847         * exception thrown by this pointcut will block the operation.
848         * </p>
849         * <p>
850         * Hooks may accept the following parameters:
851         * <ul>
852         * <li>
853         * {@link ca.cdr.api.model.json.IOAuth2ClientDetails} - The Client being saved. Pointcuts should not modify this object.
854         * </li>
855         * </ul>
856         * </p>
857         * Hook methods must return <code>void</code>.
858         */
859        SMART_OIDC_CLIENT_SAVING(void.class, IOAuth2ClientDetails.class),
860
861        /**
862         * <b>appSphere Hook:</b>
863         * The Pointcut is called when an appSphere admin updates the status of an application or service
864         * <p>
865         * This hook is called within the open database transaction used to
866         * save the object. This means that at the time this pointcut is invoked,
867         * the record does not yet appear in the database. It also means that any
868         * exception thrown by this pointcut will block the operation.
869         * </p>
870         * <p>
871         * Hooks may accept the following parameters:
872         * <ul>
873         * <li>
874         * {@link AGConsoleJson} - The application or service being updated. Pointcuts should not modify this object.
875         * </li>
876         * </ul>
877         * </p>
878         * Hook methods must return <code>void</code>.
879         */
880        AG_APPLICATION_STATUS_UPDATING(void.class, AGConsoleJson.class),
881
882        /**
883         * <b>appSphere Hook:</b>
884         * The pointcut is called after an appSphere admin updates the status of an application or service
885         * <p>
886         * This hook is called after the database transaction used to
887         * save the object has been committed. This means that the record already
888         * appears in the database. Any exceptions thrown by hooks for this
889         * pointcut may cause an error to appear for the user requesting the
890         * operation, but will not affect what has been saved in the database,
891         * so no exceptions should be thrown within this pointcut.
892         * </p>
893         * <p>
894         * Hooks may accept the following parameters:
895         * <ul>
896         * <li>
897         * {@link AGConsoleJson} - The application or service that was updated. Pointcuts should not modify this object.
898         * </li>
899         * </ul>
900         * </p>
901         * Hook methods must return <code>void</code>.
902         */
903        AG_APPLICATION_STATUS_UPDATED(void.class, AGConsoleJson.class),
904
905        /**
906         * <b>appSphere Hook:</b>
907         * The Pointcut is called when an appSphere developer registers an application, prior to commiting the registration to the database
908         * <p>
909         * This hook is called within the open database transaction used to
910         * save the object. This means that at the time this pointcut is invoked,
911         * the record does not yet appear in the database. It also means that any
912         * exception thrown by this pointcut will block the operation.
913         * </p>
914         * <p>
915         * Hooks may accept the following parameters:
916         * <ul>
917         * <li>
918         * {@link AGApplicationJson} - The application or service being registered. Pointcuts can modify this object.
919         * </li>
920         * </ul>
921         * </p>
922         * Hook methods must return <code>void</code>.
923         */
924        AG_APPLICATION_REGISTER(void.class, AGApplicationJson.class),
925
926        /**
927         * <b>appSphere Hook:</b>
928         * The Pointcut is called when an appSphere developer re-registers an application, prior to commiting the registration to the database
929         * <p>
930         * This hook is called within the open database transaction used to
931         * save the object. This means that at the time this pointcut is invoked,
932         * the record does not yet appear in the database. It also means that any
933         * exception thrown by this pointcut will block the operation.
934         * </p>
935         * <p>
936         * Hooks may accept the following parameters:
937         * <ul>
938         * <li>
939         * {@link AGApplicationJson} - The application or service being re-registered. Pointcuts can modify this object.
940         * </li>
941         * </ul>
942         * </p>
943         * Hook methods must return <code>void</code>.
944         */
945        AG_APPLICATION_RE_REGISTER(void.class, AGApplicationJson.class),
946
947        /**
948         * <b>System-to-System Data Exchange Hook:</b>
949         * This pointcut is called when doing resource matching in the $member-match operation. It provides the ability for
950         * clients to execute custom matching JavaScript for the patient matching in $member-match.
951         * <p>
952         * Hooks may accept the following parameters:
953         * <ul>
954         * <li>
955         * {@link ca.cdr.api.fhir.interceptor.IMemberMatchRequest} - the wrapper request object that contains memberPatient
956         * and CoverageToMatch Resources.
957         * </li>
958         * <li>
959         * {@link ca.uhn.fhir.rest.api.server.RequestDetails} - A bean containing details about the request that is about to
960         * be processed.
961         * </li>
962         * </ul>
963         * </p>
964         * Hook methods may return <code>Patient</code> if a matching patient is found, or <code>void</code> otherwise.
965         * Note that if <code>void</code> is returned, then the system will perform the default matching algorithm to try to
966         * find any matching patient.
967         */
968        MEMBER_MATCH(IBaseResource.class, IMemberMatchRequest.class, RequestDetails.class),
969
970        /**
971         * <b>Consent Module Hook:</b>
972         * <p>This pointcut can be used by customers to add new interpretations of Consent resources
973         * (i.e. custom implementations of an IConsentService) by specifying a <code>consentServiceFactory</code>
974         * value in the JSON configuration file.
975         * </p>
976         * <p>A fallback IConsentService can also be created to handle the scenario when no Consent resource is available
977         * for a resource. This can be done by specifying a <code>fallbackConsentRule</code> in the JSON configuration file.
978         * </p>
979         * <p>
980         * The hook will have the following parameters:
981         * <ul>
982         * <li>
983         * {@link String} the name of IConsentService that will be built. This will come from the
984         * <code>consentServiceFactory</code> or <code>fallbackConsentRule</code> properties of the
985         * JSON configuration file.
986         * </li>
987         * <li>
988         * {@link IBaseResource} the Consent resource (if present) to use to build the IConsentService.
989         * </li>
990         * </ul>
991         * </p>
992         */
993        CONSENT_BUILD_CONSENT_SERVICE(IConsentService.class, String.class, IBaseResource.class),
994
995        /**
996         * <b>Consent Hook:</b>
997         * This pointcut can be used by customers to customize the default behavior of the Consent resource-based
998         * Consent Service.
999         * Provide the string representation of the (initial) queries that should be used to fetch consent resources
1000         * given a certain request and the {@link ConsentLookupContext}.
1001         * <p>
1002         * The hook can have the following parameters:
1003         * <ul>
1004         * <li>
1005         * {@link RequestDetails} the request
1006         * </li>
1007         * <li>
1008         * {@link ConsentLookupContext} the consent context object
1009         * </li>
1010         * <li>
1011         * {@link IBaseResource} the resource to build the fetch query
1012         * </li>
1013         * <li>
1014         * {@link UserSessionDetailsJson} the user session details.
1015         * </li>
1016         * </ul>
1017         * </p>
1018         * Hook methods need to return an array of string representations for the consent queries. That should
1019         * consist in one query to have a better performance but in rare cases multiple can be provided.
1020         */
1021        CONSENT_FETCH_QUERIES(
1022                        String[].class,
1023                        RequestDetails.class,
1024                        ConsentLookupContext.class,
1025                        IBaseResource.class,
1026                        UserSessionDetailsJson.class),
1027
1028        /**
1029         * <b>Prior Auth CRD Gather context hook:</b>
1030         * This pointcut can be used by customers to customize the default behavior of the Prior Auth CRD
1031         * for determining patientId in Coverage context.
1032         * <p>
1033         * The hook can have the following parameters:
1034         * <ul>
1035         * <li>
1036         * {@link CdsServiceRequestJson} the CdsServiceRequestJson from the hook request
1037         * </li>
1038         * <li>
1039         * {@link PriorAuthCrdContextJson} the PriorAuthCrdContextJson to return result i.e. patientId
1040         * </li>
1041         * </ul>
1042         * </p>
1043         * Hook methods must return <code>void</code>.
1044         */
1045        PRIOR_AUTH_CRD_GATHER_CONTEXT(void.class, CdsServiceRequestJson.class, PriorAuthCrdContextJson.class);
1046
1047        private final List<String> myParameterTypes;
1048        private final Class<?> myReturnType;
1049        private final ExceptionHandlingSpec myExceptionHandlingSpec;
1050
1051        CdrPointcut(
1052                        @Nonnull Class<?> theReturnType,
1053                        @Nonnull ExceptionHandlingSpec theExceptionHandlingSpec,
1054                        String... theParameterTypes) {
1055
1056                // This class uses capital-B Boolean for the boolean return type
1057                assert !theReturnType.equals(boolean.class);
1058
1059                myReturnType = theReturnType;
1060                myExceptionHandlingSpec = theExceptionHandlingSpec;
1061                myParameterTypes = Collections.unmodifiableList(Arrays.asList(theParameterTypes));
1062        }
1063
1064        CdrPointcut(@Nonnull Class<?> theReturnType, String... theParameterTypes) {
1065                this(theReturnType, new ExceptionHandlingSpec(), theParameterTypes);
1066        }
1067
1068        CdrPointcut(@Nonnull Class<?> theReturnType, Class<?>... theParameterTypes) {
1069                this(theReturnType, new ExceptionHandlingSpec(), toNames(theParameterTypes));
1070        }
1071
1072        CdrPointcut(@Nonnull Class<?> theReturnType) {
1073                this(theReturnType, new ExceptionHandlingSpec(), ArrayUtils.EMPTY_STRING_ARRAY);
1074        }
1075
1076        CdrPointcut(@Nonnull Class<?> theReturnType, Class<?> theParameterTypes) {
1077                this(theReturnType, new ExceptionHandlingSpec(), theParameterTypes.getName());
1078        }
1079
1080        private static String[] toNames(Class<?>[] theParameterTypes) {
1081                return Arrays.stream(theParameterTypes)
1082                                .map(t -> t.getName())
1083                                .collect(Collectors.toList())
1084                                .toArray(new String[0]);
1085        }
1086
1087        private static Class<?> toReturnTypeClass(String theReturnType) {
1088                try {
1089                        return Class.forName(theReturnType);
1090                } catch (ClassNotFoundException theE) {
1091                        return UnknownType.class;
1092                }
1093        }
1094
1095        @Override
1096        public boolean isShouldLogAndSwallowException(@Nonnull Throwable theException) {
1097                for (Class<? extends Throwable> next : myExceptionHandlingSpec.myTypesToLogAndSwallow) {
1098                        if (next.isAssignableFrom(theException.getClass())) {
1099                                return true;
1100                        }
1101                }
1102                return false;
1103        }
1104
1105        @Override
1106        @Nonnull
1107        public Class<?> getReturnType() {
1108                return myReturnType;
1109        }
1110
1111        @Override
1112        public Class<?> getBooleanReturnTypeForEnum() {
1113                return Boolean.class;
1114        }
1115
1116        @Override
1117        @Nonnull
1118        public List<String> getParameterTypes() {
1119                return myParameterTypes;
1120        }
1121
1122        private static class UnknownType {}
1123
1124        private static class ExceptionHandlingSpec {
1125
1126                private final Set<Class<? extends Throwable>> myTypesToLogAndSwallow = new HashSet<>();
1127
1128                ExceptionHandlingSpec addLogAndSwallow(@Nonnull Class<? extends Throwable> theType) {
1129                        myTypesToLogAndSwallow.add(theType);
1130                        return this;
1131                }
1132        }
1133}