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.forum.server.search;
018
019import com.echothree.model.control.core.common.ComponentVendors;
020import com.echothree.model.control.core.common.EntityTypes;
021import com.echothree.model.control.forum.common.ForumConstants;
022import com.echothree.model.control.forum.server.control.ForumControl;
023import com.echothree.model.control.index.common.IndexConstants;
024import com.echothree.model.control.index.common.IndexFieldVariations;
025import com.echothree.model.control.index.common.IndexFields;
026import com.echothree.model.control.index.common.IndexTypes;
027import com.echothree.model.control.index.server.analysis.ForumMessageAnalyzer;
028import com.echothree.model.control.search.common.SearchSortOrders;
029import com.echothree.model.control.search.common.SearchSortDirections;
030import com.echothree.model.control.search.server.search.BaseSearchEvaluator;
031import com.echothree.model.control.search.server.search.EntityInstancePKHolder;
032import com.echothree.model.data.core.server.factory.EntityInstanceFactory;
033import com.echothree.model.data.forum.server.entity.Forum;
034import com.echothree.model.data.forum.server.entity.ForumMessageType;
035import com.echothree.model.data.forum.server.entity.ForumMessageTypePartType;
036import com.echothree.model.data.party.server.entity.Language;
037import com.echothree.model.data.search.server.entity.SearchDefaultOperator;
038import com.echothree.model.data.search.server.entity.SearchSortDirection;
039import com.echothree.model.data.search.server.entity.SearchSortOrder;
040import com.echothree.model.data.search.server.entity.SearchType;
041import com.echothree.model.data.search.server.entity.SearchUseType;
042import com.echothree.model.data.user.server.entity.UserVisit;
043import com.echothree.util.server.message.ExecutionErrorAccumulator;
044import com.echothree.util.server.persistence.Session;
045import java.sql.PreparedStatement;
046import java.util.Collections;
047import java.util.HashSet;
048import java.util.Set;
049import org.apache.lucene.analysis.Analyzer;
050import org.apache.lucene.search.SortField;
051
052public class ForumMessageSearchEvaluator
053        extends BaseSearchEvaluator {
054    
055    private Forum forum;
056    private ForumMessageType forumMessageType;
057    private boolean includeFutureForumThreads;
058    
059    /** Creates a new instance of ForumMessageSearchEvaluator */
060    public ForumMessageSearchEvaluator(UserVisit userVisit, Language language, SearchType searchType, SearchDefaultOperator searchDefaultOperator, SearchSortOrder searchSortOrder,
061            SearchSortDirection searchSortDirection, SearchUseType searchUseType, Forum forum, ForumMessageType forumMessageType) {
062        super(userVisit, searchDefaultOperator, searchType, searchSortOrder, searchSortDirection, searchUseType, ComponentVendors.ECHO_THREE.name(),
063                EntityTypes.ForumMessage.name(), IndexTypes.FORUM_MESSAGE.name(), language, null);
064        
065        this.forum = forum;
066        this.forumMessageType = forumMessageType;
067        
068        var forumControl = Session.getModelController(ForumControl.class);
069        ForumMessageTypePartType indexDefaultForumMessageTypePartType = forumControl.getIndexDefaultForumMessageTypePartType(forumMessageType);
070
071        setField(indexDefaultForumMessageTypePartType.getForumMessagePartType().getForumMessagePartTypeName());
072    }
073    
074    public EntityInstancePKHolder getEntityInstancePKHolderByForum(Forum forum) {
075        EntityInstancePKHolder entityInstancePKHolder;
076        PreparedStatement ps = EntityInstanceFactory.getInstance().prepareStatement(
077                "SELECT _PK_ " +
078                "FROM componentvendors, componentvendordetails, entitytypes, entitytypedetails, entityinstances, forummessages, forummessagedetails, forumforumthreads " +
079                "WHERE frmmsg_activedetailid = frmmsgdt_forummessagedetailid " +
080                "AND frmmsgdt_frmthrd_forumthreadid = frmfrmthrd_frmthrd_forumthreadid AND frmfrmthrd_thrutime = ? " +
081                "AND frmfrmthrd_frm_forumid = ? " +
082                "AND cvnd_activedetailid = cvndd_componentvendordetailid AND cvndd_componentvendorname = ? " +
083                "AND ent_activedetailid = entdt_entitytypedetailid " +
084                "AND cvnd_componentvendorid = entdt_cvnd_componentvendorid " +
085                "AND entdt_entitytypename = ? " +
086                "AND ent_entitytypeid = eni_ent_entitytypeid AND frmmsg_forummessageid = eni_entityuniqueid " +
087                (includeFutureForumThreads ? "" : "AND frmmsgdt_postedtime <= ?"));
088        
089        if(includeFutureForumThreads) {
090            entityInstancePKHolder = getEntityInstancePKHolderFromQuery(ps,
091                    Session.MAX_TIME, forum, ComponentVendors.ECHO_THREE.name(), EntityTypes.ForumMessage.name());
092        } else {
093            entityInstancePKHolder = getEntityInstancePKHolderFromQuery(ps,
094                    Session.MAX_TIME, forum, ComponentVendors.ECHO_THREE.name(), EntityTypes.ForumMessage.name(), session.START_TIME);
095        }
096
097        return entityInstancePKHolder;
098    }
099
100    public EntityInstancePKHolder getEntityInstancePKHolderByForumMessageType(ForumMessageType forumMessageType) {
101        EntityInstancePKHolder entityInstancePKHolder;
102        PreparedStatement ps = EntityInstanceFactory.getInstance().prepareStatement(
103                "SELECT _PK_ " +
104                "FROM componentvendors, componentvendordetails, entitytypes, entitytypedetails, entityinstances, forummessages, forummessagedetails " +
105                "WHERE frmmsg_activedetailid = frmmsgdt_forummessagedetailid " +
106                "AND frmmsgdt_frmmsgtyp_forummessagetypeid = ? " +
107                "AND cvnd_activedetailid = cvndd_componentvendordetailid AND cvndd_componentvendorname = ? " +
108                "AND ent_activedetailid = entdt_entitytypedetailid " +
109                "AND cvnd_componentvendorid = entdt_cvnd_componentvendorid " +
110                "AND entdt_entitytypename = ? " +
111                "AND ent_entitytypeid = eni_ent_entitytypeid AND frmmsg_forummessageid = eni_entityuniqueid " +
112                (includeFutureForumThreads ? "" : "AND frmmsgdt_postedtime <= ?"));
113
114        if(includeFutureForumThreads) {
115            entityInstancePKHolder = getEntityInstancePKHolderFromQuery(ps,
116                    forumMessageType, ComponentVendors.ECHO_THREE.name(), EntityTypes.ForumMessage.name());
117        } else {
118            entityInstancePKHolder = getEntityInstancePKHolderFromQuery(ps,
119                    forumMessageType, ComponentVendors.ECHO_THREE.name(), EntityTypes.ForumMessage.name(),  session.START_TIME);
120        }
121
122        return entityInstancePKHolder;
123    }
124
125    /**
126     * Returns the includeFutureForumThreads.
127     * @return the includeFutureForumThreads
128     */
129    public boolean isIncludeFutureForumThreads() {
130        return includeFutureForumThreads;
131    }
132
133    /**
134     * Sets the includeFutureForumThreads.
135     * @param includeFutureForumThreads the includeFutureForumThreads to set
136     */
137    public void setIncludeFutureForumThreads(boolean includeFutureForumThreads) {
138        this.includeFutureForumThreads = includeFutureForumThreads;
139    }
140
141    @Override
142    public SortField[] getSortFields(String searchSortOrderName) {
143        SortField[] sortFields = null;
144        boolean reverse = searchSortDirection.getLastDetail().getSearchSortDirectionName().equals(SearchSortDirections.DESCENDING.name());
145        
146        if(searchSortOrderName.equals(SearchSortOrders.SCORE.name())) {
147            sortFields = new SortField[]{
148                new SortField(null, SortField.Type.SCORE, reverse),
149                new SortField(ForumConstants.ForumMessagePartType_TITLE + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)
150            };
151        } else if(searchSortOrderName.equals(SearchSortOrders.TITLE.name())) {
152            sortFields = new SortField[]{new SortField(ForumConstants.ForumMessagePartType_TITLE + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)};
153        } else if(searchSortOrderName.equals(SearchSortOrders.POSTED_TIME.name())) {
154            sortFields = new SortField[]{new SortField(IndexFields.postedTime.name(), SortField.Type.LONG, reverse)};
155        } else if(searchSortOrderName.equals(SearchSortOrders.CREATED_TIME.name())) {
156            sortFields = new SortField[]{new SortField(IndexFields.createdTime.name(), SortField.Type.LONG, reverse)};
157        } else if(searchSortOrderName.equals(SearchSortOrders.MODIFIED_TIME.name())) {
158            sortFields = new SortField[]{new SortField(IndexFields.modifiedTime.name(), SortField.Type.LONG, reverse)};
159        }
160        
161        return sortFields;
162    }
163    
164    @Override
165    public Analyzer getAnalyzer(final ExecutionErrorAccumulator eea, final Language language) {
166        return new ForumMessageAnalyzer(eea, language, entityType);
167    }
168    
169    private static Set<String> dateTimeFields;
170    
171    static {
172        Set<String> set = new HashSet<>(1);
173
174        set.add(IndexFields.postedTime.name());
175        
176        dateTimeFields = Collections.unmodifiableSet(set);
177    }
178    
179    @Override
180    protected Set<String> getDateTimeFields() {
181        return dateTimeFields;
182    }
183
184    @Override
185    protected EntityInstancePKHolder executeSearch(final ExecutionErrorAccumulator eea) {
186        EntityInstancePKHolder resultSet = super.executeSearch(eea);
187        
188        if(resultSet == null || resultSet.size() > 0) {
189            if(q != null) {
190                if(resultSet == null || resultSet.size() > 0) {
191                    EntityInstancePKHolder entityInstancePKHolder = executeQuery(eea);
192
193                    if(resultSet == null) {
194                        resultSet = entityInstancePKHolder;
195                    } else {
196                        resultSet.retainAll(entityInstancePKHolder);
197                    }
198                }
199            }
200        }
201
202        if(resultSet == null || resultSet.size() > 0) {
203            if(forum != null) {
204                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByForum(forum);
205
206                if(resultSet == null) {
207                    resultSet = entityInstancePKHolder;
208                } else {
209                    resultSet.retainAll(entityInstancePKHolder);
210                }
211            }
212        }
213
214        if(resultSet == null || resultSet.size() > 0) {
215            if(forumMessageType != null) {
216                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByForumMessageType(forumMessageType);
217
218                if(resultSet == null) {
219                    resultSet = entityInstancePKHolder;
220                } else {
221                    resultSet.retainAll(entityInstancePKHolder);
222                }
223            }
224        }
225
226        return resultSet;
227    }
228
229}