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        }
156
157        @Bean
158        public ExceptionService exceptionService() {
159                return new ExceptionService(myContext);
160        }
161
162        @Bean(name = ISearchBuilder.SEARCH_BUILDER_BEAN_NAME)
163        @Scope("prototype")
164        public ISearchBuilder newSearchBuilder(String theResourceName, Class<? extends IBaseResource> theResourceType) {
165                return new SearchBuilder(
166                                theResourceName,
167                                myStorageSettings,
168                                myEntityManagerFactory,
169                                mySqlBuilderFactory,
170                                myDialectProvider,
171                                mySearchParamRegistry,
172                                myPartitionSettings,
173                                myInterceptorBroadcaster,
174                                myResourceTagDao,
175                                myDaoRegistry,
176                                myContext,
177                                myIdHelperService,
178                                myResourceHistoryTableDao,
179                                myJpaStorageResourceParser,
180                                theResourceType);
181        }
182
183        @Bean(name = SEARCH_TASK)
184        @Scope("prototype")
185        public SearchTask createSearchTask(SearchTaskParameters theParams) {
186                return new SearchTask(
187                                theParams,
188                                myHapiTransactionService,
189                                myContext,
190                                myInterceptorBroadcaster,
191                                mySearchBuilderFactory,
192                                mySearchResultCacheSvc,
193                                myStorageSettings,
194                                mySearchCacheSvc,
195                                myPagingProvider);
196        }
197
198        @Bean(name = CONTINUE_TASK)
199        @Scope("prototype")
200        public SearchContinuationTask createSearchContinuationTask(SearchTaskParameters theParams) {
201                return new SearchContinuationTask(
202                                theParams,
203                                myHapiTransactionService,
204                                myContext,
205                                myInterceptorBroadcaster,
206                                mySearchBuilderFactory,
207                                mySearchResultCacheSvc,
208                                myStorageSettings,
209                                mySearchCacheSvc,
210                                myPagingProvider,
211                                exceptionService() // singleton
212                                );
213        }
214
215        @PostConstruct
216        public void validateConfiguration() {
217                if (myStorageSettings.isIndexStorageOptimized()
218                                && myPartitionSettings.isPartitioningEnabled()
219                                && myPartitionSettings.isIncludePartitionInSearchHashes()) {
220                        throw new ConfigurationException(Msg.code(2525) + "Incorrect configuration. "
221                                        + "StorageSettings#isIndexStorageOptimized and PartitionSettings.isIncludePartitionInSearchHashes "
222                                        + "cannot be enabled at the same time.");
223                }
224        }
225}