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