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