001/*-
002 * #%L
003 * HAPI FHIR JPA 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.config;
021
022import ca.uhn.fhir.context.ConfigurationException;
023import ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.i18n.Msg;
025import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
026import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
027import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
028import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
029import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
030import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser;
031import ca.uhn.fhir.jpa.dao.ISearchBuilder;
032import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
033import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
034import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
035import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
036import ca.uhn.fhir.jpa.model.config.PartitionSettings;
037import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
038import ca.uhn.fhir.jpa.search.ExceptionService;
039import ca.uhn.fhir.jpa.search.ISynchronousSearchSvc;
040import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory;
041import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
042import ca.uhn.fhir.jpa.search.SearchStrategyFactory;
043import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
044import ca.uhn.fhir.jpa.search.builder.sql.SqlObjectFactory;
045import ca.uhn.fhir.jpa.search.builder.tasks.SearchContinuationTask;
046import ca.uhn.fhir.jpa.search.builder.tasks.SearchTask;
047import ca.uhn.fhir.jpa.search.builder.tasks.SearchTaskParameters;
048import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
049import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc;
050import ca.uhn.fhir.rest.server.IPagingProvider;
051import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
052import jakarta.annotation.PostConstruct;
053import org.hl7.fhir.instance.model.api.IBaseResource;
054import org.springframework.beans.factory.BeanFactory;
055import org.springframework.beans.factory.annotation.Autowired;
056import org.springframework.context.annotation.Bean;
057import org.springframework.context.annotation.Configuration;
058import org.springframework.context.annotation.Scope;
059import org.springframework.transaction.PlatformTransactionManager;
060
061@Configuration
062public class SearchConfig {
063        public static final String SEARCH_TASK = "searchTask";
064        public static final String CONTINUE_TASK = "continueTask";
065
066        @Autowired
067        private JpaStorageSettings myStorageSettings;
068
069        @Autowired
070        private HapiFhirLocalContainerEntityManagerFactoryBean myEntityManagerFactory;
071
072        @Autowired
073        private SqlObjectFactory mySqlBuilderFactory;
074
075        @Autowired
076        private HibernatePropertiesProvider myDialectProvider;
077
078        @Autowired
079        private ISearchParamRegistry mySearchParamRegistry;
080
081        @Autowired
082        private PartitionSettings myPartitionSettings;
083
084        @Autowired
085        protected IInterceptorBroadcaster myInterceptorBroadcaster;
086
087        @Autowired
088        protected IResourceTagDao myResourceTagDao;
089
090        @Autowired
091        private DaoRegistry myDaoRegistry;
092
093        @Autowired
094        private FhirContext myContext;
095
096        @Autowired
097        private IIdHelperService myIdHelperService;
098
099        @Autowired
100        private PlatformTransactionManager myManagedTxManager;
101
102        @Autowired
103        private SearchStrategyFactory mySearchStrategyFactory;
104
105        @Autowired
106        private SearchBuilderFactory mySearchBuilderFactory;
107
108        @Autowired
109        private ISearchResultCacheSvc mySearchResultCacheSvc;
110
111        @Autowired
112        private ISearchCacheSvc mySearchCacheSvc;
113
114        @Autowired
115        private IPagingProvider myPagingProvider;
116
117        @Autowired
118        private BeanFactory myBeanFactory;
119
120        @Autowired
121        private ISynchronousSearchSvc mySynchronousSearchSvc;
122
123        @Autowired
124        private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
125
126        @Autowired
127        private IRequestPartitionHelperSvc myRequestPartitionHelperService;
128
129        @Autowired
130        private HapiTransactionService myHapiTransactionService;
131
132        @Autowired
133        private IResourceHistoryTableDao myResourceHistoryTableDao;
134
135        @Autowired
136        private IJpaStorageResourceParser myJpaStorageResourceParser;
137
138        @Bean
139        public ISearchCoordinatorSvc searchCoordinatorSvc() {
140                return new SearchCoordinatorSvcImpl(
141                                myContext,
142                                myStorageSettings,
143                                myInterceptorBroadcaster,
144                                myHapiTransactionService,
145                                mySearchCacheSvc,
146                                mySearchResultCacheSvc,
147                                myDaoRegistry,
148                                mySearchBuilderFactory,
149                                mySynchronousSearchSvc,
150                                myPersistedJpaBundleProviderFactory,
151                                mySearchParamRegistry,
152                                mySearchStrategyFactory,
153                                exceptionService(),
154                                myBeanFactory,
155                                myRequestPartitionHelperService);
156        }
157
158        @Bean
159        public ExceptionService exceptionService() {
160                return new ExceptionService(myContext);
161        }
162
163        @Bean(name = ISearchBuilder.SEARCH_BUILDER_BEAN_NAME)
164        @Scope("prototype")
165        public ISearchBuilder newSearchBuilder(String theResourceName, Class<? extends IBaseResource> theResourceType) {
166                return new SearchBuilder(
167                                theResourceName,
168                                myStorageSettings,
169                                myEntityManagerFactory,
170                                mySqlBuilderFactory,
171                                myDialectProvider,
172                                mySearchParamRegistry,
173                                myPartitionSettings,
174                                myInterceptorBroadcaster,
175                                myResourceTagDao,
176                                myDaoRegistry,
177                                myContext,
178                                myIdHelperService,
179                                myResourceHistoryTableDao,
180                                myJpaStorageResourceParser,
181                                theResourceType);
182        }
183
184        @Bean(name = SEARCH_TASK)
185        @Scope("prototype")
186        public SearchTask createSearchTask(SearchTaskParameters theParams) {
187                return new SearchTask(
188                                theParams,
189                                myHapiTransactionService,
190                                myContext,
191                                myInterceptorBroadcaster,
192                                mySearchBuilderFactory,
193                                mySearchResultCacheSvc,
194                                myStorageSettings,
195                                mySearchCacheSvc,
196                                myPagingProvider);
197        }
198
199        @Bean(name = CONTINUE_TASK)
200        @Scope("prototype")
201        public SearchContinuationTask createSearchContinuationTask(SearchTaskParameters theParams) {
202                return new SearchContinuationTask(
203                                theParams,
204                                myHapiTransactionService,
205                                myContext,
206                                myInterceptorBroadcaster,
207                                mySearchBuilderFactory,
208                                mySearchResultCacheSvc,
209                                myStorageSettings,
210                                mySearchCacheSvc,
211                                myPagingProvider,
212                                exceptionService() // singleton
213                                );
214        }
215
216        @PostConstruct
217        public void validateConfiguration() {
218                if (myStorageSettings.isIndexStorageOptimized()
219                                && myPartitionSettings.isPartitioningEnabled()
220                                && myPartitionSettings.isIncludePartitionInSearchHashes()) {
221                        throw new ConfigurationException(Msg.code(2525) + "Incorrect configuration. "
222                                        + "StorageSettings#isIndexStorageOptimized and PartitionSettings.isIncludePartitionInSearchHashes "
223                                        + "cannot be enabled at the same time.");
224                }
225        }
226}