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}