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