001/*- 002 * #%L 003 * HAPI FHIR JPA - Search Parameters 004 * %% 005 * Copyright (C) 2014 - 2025 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.cache; 021 022import ca.uhn.fhir.IHapiBootOrder; 023import ca.uhn.fhir.interceptor.api.Hook; 024import ca.uhn.fhir.interceptor.api.IInterceptorService; 025import ca.uhn.fhir.interceptor.api.Pointcut; 026import jakarta.annotation.PreDestroy; 027import org.hl7.fhir.instance.model.api.IBaseResource; 028import org.springframework.beans.factory.annotation.Autowired; 029import org.springframework.context.event.ContextRefreshedEvent; 030import org.springframework.context.event.EventListener; 031import org.springframework.core.annotation.Order; 032import org.springframework.stereotype.Service; 033 034/** 035 * This interceptor watches all resource changes on the server and compares them to the {@link IResourceChangeListenerCache} 036 * entries. If the resource matches the resource type and search parameter map of that entry, then the corresponding cache 037 * will be expired so it is refreshed and listeners are notified of that change within {@link ResourceChangeListenerCacheRefresherImpl#LOCAL_REFRESH_INTERVAL_MS}. 038 */ 039@Service 040public class ResourceChangeListenerRegistryInterceptor { 041 @Autowired 042 private IInterceptorService myInterceptorBroadcaster; 043 044 @Autowired 045 private IResourceChangeListenerRegistry myResourceChangeListenerRegistry; 046 047 @EventListener(classes = {ContextRefreshedEvent.class}) 048 @Order(IHapiBootOrder.REGISTER_INTERCEPTORS) 049 public void start() { 050 myInterceptorBroadcaster.registerInterceptor(this); 051 } 052 053 @PreDestroy 054 public void stop() { 055 myInterceptorBroadcaster.unregisterInterceptor(this); 056 } 057 058 @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED) 059 public void created(IBaseResource theResource) { 060 handle(theResource); 061 } 062 063 @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED) 064 public void deleted(IBaseResource theResource) { 065 handle(theResource); 066 } 067 068 @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED) 069 public void updated(IBaseResource theResource) { 070 handle(theResource); 071 } 072 073 private void handle(IBaseResource theResource) { 074 if (theResource == null) { 075 return; 076 } 077 myResourceChangeListenerRegistry.requestRefreshIfWatching(theResource); 078 } 079}