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