001/* 002 * #%L 003 * HAPI FHIR JPA Model 004 * %% 005 * Copyright (C) 2014 - 2024 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.model.listener; 021 022import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; 023import ca.uhn.fhir.jpa.model.entity.StorageSettings; 024import ca.uhn.fhir.jpa.model.search.ISearchParamHashIdentityRegistry; 025import ca.uhn.fhir.rest.server.util.IndexedSearchParam; 026import jakarta.persistence.PostLoad; 027import jakarta.persistence.PostPersist; 028import jakarta.persistence.PostUpdate; 029import jakarta.persistence.PrePersist; 030import jakarta.persistence.PreUpdate; 031import org.springframework.beans.factory.annotation.Autowired; 032import org.springframework.context.ApplicationContext; 033 034import java.util.Optional; 035 036/** 037 * Sets <code>SP_NAME, RES_TYPE, SP_UPDATED</code> column values to null for all HFJ_SPIDX tables 038 * if storage setting {@link ca.uhn.fhir.jpa.model.entity.StorageSettings#isIndexStorageOptimized()} is enabled. 039 * <p> 040 * Using EntityListener to change HFJ_SPIDX column values right before insert/update to database. 041 * </p> 042 * <p> 043 * As <code>SP_NAME, RES_TYPE</code> values could still be used after merge/persist to database, we are restoring 044 * them from <code>HASH_IDENTITY</code> value. 045 *</p> 046 * See {@link ca.uhn.fhir.jpa.model.entity.StorageSettings#setIndexStorageOptimized(boolean)} 047 */ 048public class IndexStorageOptimizationListener { 049 050 public IndexStorageOptimizationListener( 051 @Autowired StorageSettings theStorageSettings, @Autowired ApplicationContext theApplicationContext) { 052 this.myStorageSettings = theStorageSettings; 053 this.myApplicationContext = theApplicationContext; 054 } 055 056 private final StorageSettings myStorageSettings; 057 private final ApplicationContext myApplicationContext; 058 059 @PrePersist 060 @PreUpdate 061 public void optimizeSearchParams(Object theEntity) { 062 if (myStorageSettings.isIndexStorageOptimized() && theEntity instanceof BaseResourceIndexedSearchParam) { 063 ((BaseResourceIndexedSearchParam) theEntity).optimizeIndexStorage(); 064 } 065 } 066 067 @PostLoad 068 @PostPersist 069 @PostUpdate 070 public void restoreSearchParams(Object theEntity) { 071 if (myStorageSettings.isIndexStorageOptimized() && theEntity instanceof BaseResourceIndexedSearchParam) { 072 restoreSearchParams((BaseResourceIndexedSearchParam) theEntity); 073 } 074 } 075 076 /** 077 * As <code>SP_NAME, RES_TYPE</code> values could still be used after merge/persist to database (mostly by tests), 078 * we are restoring them from <code>HASH_IDENTITY</code> value. 079 * Note that <code>SP_NAME, RES_TYPE</code> values are not recovered if 080 * {@link ca.uhn.fhir.jpa.model.entity.StorageSettings#isIndexOnContainedResources()} or 081 * {@link ca.uhn.fhir.jpa.model.entity.StorageSettings#isIndexOnContainedResourcesRecursively()} 082 * settings are enabled. 083 */ 084 private void restoreSearchParams(BaseResourceIndexedSearchParam theResourceIndexedSearchParam) { 085 // getting ISearchParamHashIdentityRegistry from the App Context as it is initialized after EntityListeners 086 ISearchParamHashIdentityRegistry searchParamRegistry = 087 myApplicationContext.getBean(ISearchParamHashIdentityRegistry.class); 088 Optional<IndexedSearchParam> indexedSearchParamOptional = 089 searchParamRegistry.getIndexedSearchParamByHashIdentity( 090 theResourceIndexedSearchParam.getHashIdentity()); 091 092 if (indexedSearchParamOptional.isPresent()) { 093 theResourceIndexedSearchParam.setResourceType( 094 indexedSearchParamOptional.get().getResourceType()); 095 theResourceIndexedSearchParam.restoreParamName( 096 indexedSearchParamOptional.get().getParameterName()); 097 } 098 } 099}