001// --------------------------------------------------------------------------------
002// Copyright 2002-2024 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.search.server.logic;
018
019import com.echothree.model.control.core.server.control.CoreControl;
020import com.echothree.model.control.search.common.exception.DuplicateSearchResultActionException;
021import com.echothree.model.control.search.common.exception.UnknownCachedExecutedSearchResultException;
022import com.echothree.model.control.search.common.exception.UnknownDefaultSearchDefaultOperatorException;
023import com.echothree.model.control.search.common.exception.UnknownDefaultSearchSortDirectionException;
024import com.echothree.model.control.search.common.exception.UnknownDefaultSearchSortOrderException;
025import com.echothree.model.control.search.common.exception.UnknownSearchDefaultOperatorNameException;
026import com.echothree.model.control.search.common.exception.UnknownSearchKindNameException;
027import com.echothree.model.control.search.common.exception.UnknownSearchResultActionTypeNameException;
028import com.echothree.model.control.search.common.exception.UnknownSearchResultException;
029import com.echothree.model.control.search.common.exception.UnknownSearchSortDirectionNameException;
030import com.echothree.model.control.search.common.exception.UnknownSearchSortOrderNameException;
031import com.echothree.model.control.search.common.exception.UnknownSearchTypeNameException;
032import com.echothree.model.control.search.common.exception.UnknownSearchUseTypeNameException;
033import com.echothree.model.control.search.common.exception.UnknownUserVisitSearchException;
034import com.echothree.model.control.search.server.control.SearchControl;
035import com.echothree.model.control.search.server.database.CachedSearchToInvalidateQuery;
036import com.echothree.model.control.search.server.database.CachedSearchToInvalidateResult;
037import com.echothree.model.data.index.server.entity.Index;
038import com.echothree.model.data.search.server.entity.CachedExecutedSearch;
039import com.echothree.model.data.search.server.entity.CachedSearch;
040import com.echothree.model.data.search.server.entity.Search;
041import com.echothree.model.data.search.server.entity.SearchDefaultOperator;
042import com.echothree.model.data.search.server.entity.SearchKind;
043import com.echothree.model.data.search.server.entity.SearchResultAction;
044import com.echothree.model.data.search.server.entity.SearchResultActionType;
045import com.echothree.model.data.search.server.entity.SearchSortDirection;
046import com.echothree.model.data.search.server.entity.SearchSortOrder;
047import com.echothree.model.data.search.server.entity.SearchType;
048import com.echothree.model.data.search.server.entity.SearchUseType;
049import com.echothree.model.data.search.server.entity.UserVisitSearch;
050import com.echothree.model.data.user.server.entity.UserVisit;
051import com.echothree.util.common.message.ExecutionErrors;
052import com.echothree.util.common.persistence.BasePK;
053import com.echothree.util.server.control.BaseLogic;
054import com.echothree.util.server.message.ExecutionErrorAccumulator;
055import com.echothree.util.server.persistence.BaseEntity;
056import com.echothree.util.server.persistence.Session;
057
058public class SearchLogic
059        extends BaseLogic {
060
061    private SearchLogic() {
062        super();
063    }
064
065    private static class SearchLogicHolder {
066        static SearchLogic instance = new SearchLogic();
067    }
068
069    public static SearchLogic getInstance() {
070        return SearchLogicHolder.instance;
071    }
072    
073    public SearchDefaultOperator getSearchDefaultOperatorByName(final ExecutionErrorAccumulator eea, final String searchDefaultOperatorName) {
074        var searchControl = Session.getModelController(SearchControl.class);
075        SearchDefaultOperator searchDefaultOperator = searchControl.getSearchDefaultOperatorByName(searchDefaultOperatorName);
076
077        if(searchDefaultOperator == null) {
078            handleExecutionError(UnknownSearchDefaultOperatorNameException.class, eea, ExecutionErrors.UnknownSearchDefaultOperatorName.name(), searchDefaultOperatorName);
079        }
080
081        return searchDefaultOperator;
082    }
083    
084    public SearchDefaultOperator getDefaultSearchDefaultOperator(final ExecutionErrorAccumulator eea) {
085        var searchControl = Session.getModelController(SearchControl.class);
086        SearchDefaultOperator searchDefaultOperator = searchControl.getDefaultSearchDefaultOperator();
087
088        if(searchDefaultOperator == null) {
089            handleExecutionError(UnknownDefaultSearchDefaultOperatorException.class, eea, ExecutionErrors.UnknownDefaultSearchDefaultOperator.name());
090        }
091
092        return searchDefaultOperator;
093    }
094
095    public SearchSortDirection getSearchSortDirectionByName(final ExecutionErrorAccumulator eea, final String searchSortDirectionName) {
096        var searchControl = Session.getModelController(SearchControl.class);
097        SearchSortDirection searchSortDirection = searchControl.getSearchSortDirectionByName(searchSortDirectionName);
098
099        if(searchSortDirection == null) {
100            handleExecutionError(UnknownSearchSortDirectionNameException.class, eea, ExecutionErrors.UnknownSearchSortDirectionName.name(), searchSortDirectionName);
101        }
102
103        return searchSortDirection;
104    }
105    
106    public SearchSortDirection getDefaultSearchSortDirection(final ExecutionErrorAccumulator eea) {
107        var searchControl = Session.getModelController(SearchControl.class);
108        SearchSortDirection searchSortDirection = searchControl.getDefaultSearchSortDirection();
109
110        if(searchSortDirection == null) {
111            handleExecutionError(UnknownDefaultSearchSortDirectionException.class, eea, ExecutionErrors.UnknownDefaultSearchSortDirection.name());
112        }
113
114        return searchSortDirection;
115    }
116
117    public SearchUseType getSearchUseTypeByName(final ExecutionErrorAccumulator eea, final String searchUseTypeName) {
118        var searchControl = Session.getModelController(SearchControl.class);
119        SearchUseType searchUseType = searchControl.getSearchUseTypeByName(searchUseTypeName);
120
121        if(searchUseType == null) {
122            handleExecutionError(UnknownSearchUseTypeNameException.class, eea, ExecutionErrors.UnknownSearchUseTypeName.name(), searchUseTypeName);
123        }
124
125        return searchUseType;
126    }
127    
128    public SearchResultActionType getSearchResultActionTypeByName(final ExecutionErrorAccumulator eea, final String searchResultActionTypeName) {
129        var searchControl = Session.getModelController(SearchControl.class);
130        SearchResultActionType searchResultActionType = searchControl.getSearchResultActionTypeByName(searchResultActionTypeName);
131
132        if(searchResultActionType == null) {
133            handleExecutionError(UnknownSearchResultActionTypeNameException.class, eea, ExecutionErrors.UnknownSearchResultActionTypeName.name(), searchResultActionTypeName);
134        }
135
136        return searchResultActionType;
137    }
138    
139    public SearchKind getSearchKindByName(final ExecutionErrorAccumulator eea, final String searchKindName) {
140        var searchControl = Session.getModelController(SearchControl.class);
141        SearchKind searchKind = searchControl.getSearchKindByName(searchKindName);
142
143        if(searchKind == null) {
144            handleExecutionError(UnknownSearchKindNameException.class, eea, ExecutionErrors.UnknownSearchKindName.name(), searchKindName);
145        }
146
147        return searchKind;
148    }
149
150    public SearchType getSearchTypeByName(final ExecutionErrorAccumulator eea, final SearchKind searchKind, final String searchTypeName) {
151        var searchControl = Session.getModelController(SearchControl.class);
152        SearchType searchType = searchControl.getSearchTypeByName(searchKind, searchTypeName);
153
154        if(searchType == null) {
155            handleExecutionError(UnknownSearchTypeNameException.class, eea, ExecutionErrors.UnknownSearchTypeName.name(),
156                    searchKind.getLastDetail().getSearchKindName(), searchTypeName);
157        }
158
159        return searchType;
160    }
161
162    public SearchType getSearchTypeByName(final ExecutionErrorAccumulator eea, final String searchKindName, final String searchTypeName) {
163        SearchKind searchKind = getSearchKindByName(eea, searchKindName);
164        
165        return hasExecutionErrors(eea) ? null : getSearchTypeByName(eea, searchKind, searchTypeName);
166    }
167    
168    public SearchSortOrder getSearchSortOrderByName(final ExecutionErrorAccumulator eea, final SearchKind searchKind, final String searchSortOrderName) {
169        var searchControl = Session.getModelController(SearchControl.class);
170        SearchSortOrder searchSortOrder = searchControl.getSearchSortOrderByName(searchKind, searchSortOrderName);
171
172        if(searchSortOrder == null) {
173            handleExecutionError(UnknownSearchSortOrderNameException.class, eea, ExecutionErrors.UnknownSearchSortOrderName.name(),
174                    searchKind.getLastDetail().getSearchKindName(), searchSortOrderName);
175        }
176
177        return searchSortOrder;
178    }
179
180    public SearchSortOrder getSearchSortOrderByName(final ExecutionErrorAccumulator eea, final String searchKindName, final String searchSortOrderName) {
181        SearchKind searchKind = getSearchKindByName(eea, searchKindName);
182        
183        return hasExecutionErrors(eea) ? null : getSearchSortOrderByName(eea, searchKind, searchSortOrderName);
184    }
185    
186    public SearchSortOrder getDefaultSearchSortOrder(final ExecutionErrorAccumulator eea, final SearchKind searchKind) {
187        var searchControl = Session.getModelController(SearchControl.class);
188        SearchSortOrder searchSortOrder = searchControl.getDefaultSearchSortOrder(searchKind);
189
190        if(searchSortOrder == null) {
191            handleExecutionError(UnknownDefaultSearchSortOrderException.class, eea, ExecutionErrors.UnknownDefaultSearchSortOrder.name(),
192                    searchKind.getLastDetail().getSearchKindName());
193        }
194
195        return searchSortOrder;
196    }
197
198    public SearchSortOrder getDefaultSearchSortOrder(final ExecutionErrorAccumulator eea, final String searchKindName) {
199        SearchKind searchKind = getSearchKindByName(eea, searchKindName);
200        
201        return hasExecutionErrors(eea) ? null : getDefaultSearchSortOrder(eea, searchKind);
202    }
203    
204    public UserVisitSearch getUserVisitSearch(final ExecutionErrorAccumulator eea, final UserVisit userVisit, final SearchType searchType) {
205        var searchControl = Session.getModelController(SearchControl.class);
206        UserVisitSearch userVisitSearch = searchControl.getUserVisitSearch(userVisit, searchType);
207        
208        if(userVisitSearch == null) {
209            handleExecutionError(UnknownUserVisitSearchException.class, eea, ExecutionErrors.UnknownUserVisitSearch.name());
210        }
211        
212        return userVisitSearch;
213    }
214    
215    public UserVisitSearch getUserVisitSearchByName(final ExecutionErrorAccumulator eea, final UserVisit userVisit, final String searchKindName,
216            final String searchTypeName) {
217        SearchType searchType = getSearchTypeByName(eea, searchKindName, searchTypeName);
218        UserVisitSearch userVisitSearch = hasExecutionErrors(eea) ? null : getUserVisitSearch(eea, userVisit, searchType);
219        
220        return userVisitSearch;
221    }
222    
223    public void removeUserVisitSearch(final ExecutionErrorAccumulator eea, final UserVisit userVisit, final String searchKindName,
224            final String searchTypeName) {
225        var searchControl = Session.getModelController(SearchControl.class);
226        UserVisitSearch userVisitSearch = getUserVisitSearchByName(eea, userVisit, searchKindName, searchTypeName);
227
228        if(!hasExecutionErrors(eea)) {
229            searchControl.removeUserVisitSearch(userVisitSearch);
230        }
231    }
232    
233    public Long countSearchResults(final Search search) {
234        var searchControl = Session.getModelController(SearchControl.class);
235        CachedSearch cachedSearch = search.getCachedSearch();
236        long count;
237        
238        if(cachedSearch == null) {
239            count = searchControl.countSearchResults(search);
240        } else {
241            CachedExecutedSearch cachedExecutedSearch = searchControl.getCachedExecutedSearch(cachedSearch);
242            
243            count = searchControl.countCachedExecutedSearchResults(cachedExecutedSearch);
244        }
245        
246        return count;
247    }
248    
249    public Long countUserVisitSearchResults(final ExecutionErrorAccumulator eea, final UserVisit userVisit, final String searchKindName,
250            final String searchTypeName) {
251        UserVisitSearch userVisitSearch = getUserVisitSearchByName(eea, userVisit, searchKindName, searchTypeName);
252        Long count = hasExecutionErrors(eea) ? null : countSearchResults(userVisitSearch.getSearch());
253
254        return count;
255    }
256    
257    public SearchResultAction createSearchResultAction(final ExecutionErrorAccumulator eea, final UserVisit userVisit, final String searchKindName,
258            final String searchTypeName, final String searchResultActionTypeName, final BaseEntity baseEntity, final BasePK createdBy) {
259        SearchResultAction itemSearchResultAction = null;
260        var userVisitSearch = getUserVisitSearchByName(eea, userVisit, searchKindName, searchTypeName);
261
262        if(eea == null || !eea.hasExecutionErrors()) {
263            var searchResultActionType = getSearchResultActionTypeByName(eea, searchResultActionTypeName);
264            
265            if(eea == null || !eea.hasExecutionErrors()) {
266                var coreControl = Session.getModelController(CoreControl.class);
267                var searchControl = Session.getModelController(SearchControl.class);
268                var search = userVisitSearch.getSearch();
269                var cachedSearch = search.getCachedSearch();
270                var basePK = baseEntity.getPrimaryKey();
271                var entityInstance = coreControl.getEntityInstanceByBasePK(basePK);
272
273                if(cachedSearch == null) {
274                    if(!searchControl.searchResultExists(search, entityInstance)) {
275                        handleExecutionError(UnknownSearchResultException.class, eea, ExecutionErrors.UnknownSearchResult.name(),
276                                searchKindName, searchTypeName, basePK.getEntityRef());
277                    }
278                } else {
279                    var cachedExecutedSearch = searchControl.getCachedExecutedSearch(cachedSearch);
280
281                    if(!searchControl.cachedExecutedSearchResultExists(cachedExecutedSearch, entityInstance)) {
282                        handleExecutionError(UnknownCachedExecutedSearchResultException.class, eea, ExecutionErrors.UnknownCachedExecutedSearchResult.name(),
283                                searchKindName, searchTypeName, basePK.getEntityRef());
284                    }
285                }
286
287                if(eea == null || !eea.hasExecutionErrors()) {
288                    if(searchControl.searchResultActionExists(search, searchResultActionType, entityInstance)) {
289                        handleExecutionError(DuplicateSearchResultActionException.class, eea, ExecutionErrors.DuplicateSearchResultAction.name(),
290                                searchKindName, searchTypeName, searchResultActionTypeName, basePK.getEntityRef());
291                    } else {
292                        searchControl.createSearchResultAction(search, searchResultActionType, getSession().START_TIME_LONG, entityInstance, createdBy);
293                    }
294                }
295            }
296        }
297        
298        return itemSearchResultAction;
299    }
300    
301    public void invalidateCachedSearchesByIndex(Index index) {
302        for(CachedSearchToInvalidateResult cachedSearchToInvalidateResult : new CachedSearchToInvalidateQuery().execute(index)) {
303            cachedSearchToInvalidateResult.getCachedSearchStatus().setIsConsistent(Boolean.FALSE);
304        }
305    }
306    
307}