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