001/*- 002 * #%L 003 * HAPI FHIR Subscription Server 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.topic; 021 022import ca.uhn.fhir.cache.BaseResourceCacheSynchronizer; 023import ca.uhn.fhir.context.FhirContext; 024import ca.uhn.fhir.context.FhirVersionEnum; 025import ca.uhn.fhir.i18n.Msg; 026import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 027import ca.uhn.fhir.rest.param.TokenParam; 028import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; 029import ca.uhn.fhir.subscription.SubscriptionConstants; 030import ca.uhn.fhir.util.Logs; 031import jakarta.annotation.Nonnull; 032import org.hl7.fhir.instance.model.api.IBaseResource; 033import org.hl7.fhir.r5.model.Enumerations; 034import org.hl7.fhir.r5.model.SubscriptionTopic; 035import org.slf4j.Logger; 036import org.springframework.beans.factory.annotation.Autowired; 037import org.springframework.context.event.ContextRefreshedEvent; 038import org.springframework.context.event.EventListener; 039 040import java.util.HashSet; 041import java.util.List; 042import java.util.Set; 043 044public class SubscriptionTopicLoader extends BaseResourceCacheSynchronizer { 045 private static final Logger ourLog = Logs.getSubscriptionTopicLog(); 046 047 @Autowired 048 private FhirContext myFhirContext; 049 050 @Autowired 051 private SubscriptionTopicRegistry mySubscriptionTopicRegistry; 052 053 @Autowired 054 protected ISearchParamRegistry mySearchParamRegistry; 055 056 /** 057 * Constructor 058 */ 059 public SubscriptionTopicLoader() { 060 super("SubscriptionTopic"); 061 } 062 063 @Override 064 @EventListener(classes = ContextRefreshedEvent.class) 065 public void registerListener() { 066 if (!myFhirContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4B)) { 067 return; 068 } 069 super.registerListener(); 070 } 071 072 @Override 073 @Nonnull 074 protected SearchParameterMap getSearchParameterMap() { 075 SearchParameterMap map = new SearchParameterMap(); 076 077 if (mySearchParamRegistry.getActiveSearchParam( 078 "SubscriptionTopic", "status", ISearchParamRegistry.SearchParamLookupContextEnum.ALL) 079 != null) { 080 map.add(SubscriptionTopic.SP_STATUS, new TokenParam(null, Enumerations.PublicationStatus.ACTIVE.toCode())); 081 } 082 map.setLoadSynchronousUpTo(SubscriptionConstants.MAX_SUBSCRIPTION_RESULTS); 083 return map; 084 } 085 086 @Override 087 protected void handleInit(List<IBaseResource> resourceList) { 088 updateSubscriptionTopicRegistry(resourceList); 089 } 090 091 @Override 092 protected int syncResourcesIntoCache(List<IBaseResource> resourceList) { 093 return updateSubscriptionTopicRegistry(resourceList); 094 } 095 096 private int updateSubscriptionTopicRegistry(List<IBaseResource> theResourceList) { 097 Set<String> allIds = new HashSet<>(); 098 int registeredCount = 0; 099 100 for (IBaseResource resource : theResourceList) { 101 String nextId = resource.getIdElement().getIdPart(); 102 allIds.add(nextId); 103 104 boolean registered = mySubscriptionTopicRegistry.register(normalizeToR5(resource)); 105 if (registered) { 106 registeredCount++; 107 } 108 } 109 110 mySubscriptionTopicRegistry.unregisterAllIdsNotInCollection(allIds); 111 ourLog.debug("Finished sync subscription topics - registered {}", registeredCount); 112 return registeredCount; 113 } 114 115 private SubscriptionTopic normalizeToR5(IBaseResource theResource) { 116 if (theResource instanceof SubscriptionTopic) { 117 return (SubscriptionTopic) theResource; 118 } else if (theResource instanceof org.hl7.fhir.r4b.model.SubscriptionTopic) { 119 return SubscriptionTopicCanonicalizer.canonicalizeTopic(myFhirContext, theResource); 120 } else { 121 throw new IllegalArgumentException(Msg.code(2332) 122 + "Only R4B and R5 SubscriptionTopic is currently supported. Found " + theResource.getClass()); 123 } 124 } 125}