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.item.server.search; 018 019import com.echothree.model.control.core.common.ComponentVendors; 020import com.echothree.model.control.core.common.EntityTypes; 021import com.echothree.model.control.index.common.IndexConstants; 022import com.echothree.model.control.index.common.IndexFieldVariations; 023import com.echothree.model.control.index.common.IndexFields; 024import com.echothree.model.control.index.common.IndexTypes; 025import com.echothree.model.control.index.server.analysis.ItemAnalyzer; 026import com.echothree.model.control.item.common.ItemConstants; 027import com.echothree.model.control.item.server.control.ItemControl; 028import com.echothree.model.control.item.server.logic.ItemDescriptionLogic; 029import com.echothree.model.control.search.common.SearchSortOrders; 030import com.echothree.model.control.search.common.SearchSortDirections; 031import com.echothree.model.control.search.server.search.BaseSearchEvaluator; 032import com.echothree.model.control.search.server.search.EntityInstancePKHolder; 033import com.echothree.model.data.core.server.factory.EntityInstanceFactory; 034import com.echothree.model.data.item.server.entity.Item; 035import com.echothree.model.data.item.server.entity.ItemType; 036import com.echothree.model.data.item.server.entity.ItemUseType; 037import com.echothree.model.data.party.server.entity.Language; 038import com.echothree.model.data.search.server.entity.SearchDefaultOperator; 039import com.echothree.model.data.search.server.entity.SearchSortDirection; 040import com.echothree.model.data.search.server.entity.SearchSortOrder; 041import com.echothree.model.data.search.server.entity.SearchType; 042import com.echothree.model.data.search.server.entity.SearchUseType; 043import com.echothree.model.data.user.server.entity.UserVisit; 044import com.echothree.model.data.workflow.server.entity.WorkflowStep; 045import com.echothree.util.server.message.ExecutionErrorAccumulator; 046import com.echothree.util.server.persistence.Session; 047import java.util.List; 048import org.apache.lucene.analysis.Analyzer; 049import org.apache.lucene.search.SortField; 050 051public class ItemSearchEvaluator 052 extends BaseSearchEvaluator { 053 054 private String itemNameOrAlias; 055 private ItemType itemType; 056 private ItemUseType itemUseType; 057 private WorkflowStep itemStatusWorkflowStep; 058 List<WorkflowStep> itemStatusWorkflowSteps; 059 060 /** Creates a new instance of ItemSearchEvaluator */ 061 public ItemSearchEvaluator(UserVisit userVisit, Language language, SearchType searchType, SearchDefaultOperator searchDefaultOperator, SearchSortOrder searchSortOrder, 062 SearchSortDirection searchSortDirection, SearchUseType searchUseType) { 063 super(userVisit, searchDefaultOperator, searchType, searchSortOrder, searchSortDirection, searchUseType, ComponentVendors.ECHO_THREE.name(), 064 EntityTypes.Item.name(), IndexTypes.ITEM.name(), language, null); 065 066 setField(ItemDescriptionLogic.getInstance().getIndexDefaultItemDescriptionTypeName()); 067 } 068 069 /** Counts the number of search parameters. */ 070 @Override 071 protected int countParameters() { 072 return super.countParameters() + (itemNameOrAlias == null ? 0 : 1) + (itemType == null ? 0 : 1) 073 + (itemUseType == null ? 0 : 1) + (itemStatusWorkflowStep == null ? 0 : 1) + (itemStatusWorkflowSteps == null ? 0 : 1); 074 } 075 076 /** Determines if the result of the search may be cached. For Items, the only field that may be used is the description, "q." If any 077 * others are utilized, the result may not be cached. 078 */ 079 @Override 080 protected boolean isResultCachable() { 081 return countParameters() == 1 && q != null; 082 } 083 084 public EntityInstancePKHolder getEntityInstancePKHolderByItemType(ItemType itemType) { 085 return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement( 086 "SELECT _PK_ " + 087 "FROM entityinstances, items, itemdetails " + 088 "WHERE itm_activedetailid = itmdt_itemdetailid AND itmdt_ityp_itemtypeid = ? " + 089 "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid"), 090 itemType, entityType); 091 } 092 093 public EntityInstancePKHolder getEntityInstancePKHolderByItemUseType(ItemUseType itemUseType) { 094 return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement( 095 "SELECT _PK_ " + 096 "FROM entityinstances, items, itemdetails " + 097 "WHERE itm_activedetailid = itmdt_itemdetailid AND itmdt_iutyp_itemusetypeid = ? " + 098 "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid"), 099 itemUseType, entityType); 100 } 101 102 public EntityInstancePKHolder getEntityInstancePKHolderByItemStatusWorkflowStep(WorkflowStep itemStatusWorkflowStep) { 103 return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement( 104 "SELECT _PK_ " + 105 "FROM entityinstances, items, itemdetails, workflowentitystatuses " + 106 "WHERE itm_activedetailid = itmdt_itemdetailid " + 107 "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid " + 108 "AND eni_entityinstanceid = wkfles_eni_entityinstanceid AND wkfles_wkfls_workflowstepid = ? AND wkfles_thrutime = ?"), 109 entityType, itemStatusWorkflowStep, Session.MAX_TIME); 110 } 111 112 /** 113 * Returns the itemNameOrAlias. 114 * @return the itemNameOrAlias 115 */ 116 public String getItemNameOrAlias() { 117 return itemNameOrAlias; 118 } 119 120 /** 121 * Sets the itemNameOrAlias. 122 * @param itemNameOrAlias the itemNameOrAlias to set 123 */ 124 public void setItemNameOrAlias(String itemNameOrAlias) { 125 this.itemNameOrAlias = itemNameOrAlias; 126 } 127 128 /** 129 * Returns the itemType. 130 * @return the itemType 131 */ 132 public ItemType getItemType() { 133 return itemType; 134 } 135 136 /** 137 * Sets the itemType. 138 * @param itemType the itemType to set 139 */ 140 public void setItemType(ItemType itemType) { 141 this.itemType = itemType; 142 } 143 144 /** 145 * Returns the itemUseType. 146 * @return the itemUseType 147 */ 148 public ItemUseType getItemUseType() { 149 return itemUseType; 150 } 151 152 /** 153 * Sets the itemUseType. 154 * @param itemUseType the itemUseType to set 155 */ 156 public void setItemUseType(ItemUseType itemUseType) { 157 this.itemUseType = itemUseType; 158 } 159 160 /** 161 * Returns the itemStatusWorkflowStep. 162 * @return the itemStatusWorkflowStep 163 */ 164 public WorkflowStep getItemStatusWorkflowStep() { 165 return itemStatusWorkflowStep; 166 } 167 168 /** 169 * Sets the itemStatusWorkflowStep. 170 * @param itemStatusWorkflowStep the itemStatusWorkflowStep to set 171 */ 172 public void setItemStatusWorkflowStep(WorkflowStep itemStatusWorkflowStep) { 173 this.itemStatusWorkflowStep = itemStatusWorkflowStep; 174 } 175 176 /** 177 * Sets the itemStatusWorkflowSteps. 178 * @param itemStatusWorkflowSteps the itemStatusWorkflowSteps to set 179 */ 180 public void setItemStatusWorkflowSteps(List<WorkflowStep> itemStatusWorkflowSteps) { 181 this.itemStatusWorkflowSteps = itemStatusWorkflowSteps; 182 } 183 184 @Override 185 public SortField[] getSortFields(String searchSortOrderName) { 186 SortField[] sortFields = null; 187 boolean reverse = searchSortDirection.getLastDetail().getSearchSortDirectionName().equals(SearchSortDirections.DESCENDING.name()); 188 189 if(searchSortOrderName.equals(SearchSortOrders.SCORE.name())) { 190 sortFields = new SortField[]{ 191 new SortField(null, SortField.Type.SCORE, reverse), 192 new SortField(ItemConstants.ItemDescriptionType_DEFAULT_DESCRIPTION + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse) 193 }; 194 } else if(searchSortOrderName.equals(SearchSortOrders.DEFAULT_DESCRIPTION.name())) { 195 sortFields = new SortField[]{new SortField(ItemConstants.ItemDescriptionType_DEFAULT_DESCRIPTION + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)}; 196 } else if(searchSortOrderName.equals(SearchSortOrders.ITEM_NAME.name())) { 197 sortFields = new SortField[]{new SortField(IndexFields.itemName.name() + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)}; 198 } else if(searchSortOrderName.equals(SearchSortOrders.CREATED_TIME.name())) { 199 sortFields = new SortField[]{new SortField(IndexFields.createdTime.name(), SortField.Type.LONG, reverse)}; 200 } else if(searchSortOrderName.equals(SearchSortOrders.MODIFIED_TIME.name())) { 201 sortFields = new SortField[]{new SortField(IndexFields.modifiedTime.name(), SortField.Type.LONG, reverse)}; 202 } 203 204 return sortFields; 205 } 206 207 @Override 208 public Analyzer getAnalyzer(final ExecutionErrorAccumulator eea, final Language language) { 209 return new ItemAnalyzer(eea, language, entityType); 210 } 211 212 @Override 213 protected EntityInstancePKHolder executeSearch(final ExecutionErrorAccumulator eea) { 214 EntityInstancePKHolder resultSet = null; 215 216 if(itemNameOrAlias == null) { 217 resultSet = super.executeSearch(eea); 218 219 if(resultSet == null || resultSet.size() > 0) { 220 if(q != null) { 221 if(resultSet == null || resultSet.size() > 0) { 222 EntityInstancePKHolder entityInstancePKHolder = executeQuery(eea); 223 224 if(resultSet == null) { 225 resultSet = entityInstancePKHolder; 226 } else { 227 resultSet.retainAll(entityInstancePKHolder); 228 } 229 } 230 } 231 } 232 233 if(resultSet == null || resultSet.size() > 0) { 234 if(itemType != null) { 235 EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemType(itemType); 236 237 if(resultSet == null) { 238 resultSet = entityInstancePKHolder; 239 } else { 240 resultSet.retainAll(entityInstancePKHolder); 241 } 242 } 243 } 244 245 if(resultSet == null || resultSet.size() > 0) { 246 if(itemUseType != null) { 247 EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemUseType(itemUseType); 248 249 if(resultSet == null) { 250 resultSet = entityInstancePKHolder; 251 } else { 252 resultSet.retainAll(entityInstancePKHolder); 253 } 254 } 255 } 256 257 if(resultSet == null || resultSet.size() > 0) { 258 if(itemStatusWorkflowStep != null) { 259 EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemStatusWorkflowStep(itemStatusWorkflowStep); 260 261 if(resultSet == null) { 262 resultSet = entityInstancePKHolder; 263 } else { 264 resultSet.retainAll(entityInstancePKHolder); 265 } 266 } 267 } 268 269 if(resultSet == null || resultSet.size() > 0) { 270 if(itemStatusWorkflowSteps != null) { 271 EntityInstancePKHolder entityInstancePKHolder = null; 272 273 for(var workflowStep : itemStatusWorkflowSteps) { 274 EntityInstancePKHolder individualPKHolder = getEntityInstancePKHolderByItemStatusWorkflowStep(workflowStep); 275 276 if(entityInstancePKHolder == null) { 277 entityInstancePKHolder = individualPKHolder; 278 } else { 279 entityInstancePKHolder.addAll(individualPKHolder); 280 } 281 } 282 283 if(resultSet == null) { 284 resultSet = entityInstancePKHolder; 285 } else { 286 resultSet.retainAll(entityInstancePKHolder); 287 } 288 } 289 } 290 } else { 291 var itemControl = Session.getModelController(ItemControl.class); 292 Item item = itemControl.getItemByNameThenAlias(itemNameOrAlias); 293 294 if(item != null) { 295 resultSet = new EntityInstancePKHolder(1); 296 resultSet.add(getCoreControl().getEntityInstanceByBasePK(item.getPrimaryKey()).getPrimaryKey(), null); 297 } 298 } 299 300 return resultSet; 301 } 302 303}