001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 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.indexer; 018 019import com.echothree.model.control.core.common.MimeTypeUsageTypes; 020import com.echothree.model.control.index.common.IndexConstants; 021import com.echothree.model.control.index.common.IndexFieldVariations; 022import com.echothree.model.control.index.common.IndexFields; 023import com.echothree.model.control.item.server.analyzer.ItemAnalyzer; 024import com.echothree.model.control.index.server.indexer.BaseIndexer; 025import com.echothree.model.control.index.server.indexer.FieldTypes; 026import com.echothree.model.control.index.server.indexer.IndexerDebugFlags; 027import com.echothree.model.control.index.server.indexer.sortabledescriptionproducer.SortableDescriptionProducer; 028import com.echothree.model.control.index.server.indexer.sortabledescriptionproducer.SortableDescriptionProducerFactory; 029import com.echothree.model.control.item.server.control.ItemControl; 030import com.echothree.model.data.core.server.entity.EntityInstance; 031import com.echothree.model.data.index.server.entity.Index; 032import com.echothree.model.data.item.server.entity.Item; 033import com.echothree.model.data.item.server.entity.ItemDescriptionType; 034import com.echothree.util.server.message.ExecutionErrorAccumulator; 035import com.echothree.util.server.persistence.Session; 036import java.util.List; 037import org.apache.lucene.analysis.Analyzer; 038import org.apache.lucene.document.Document; 039import org.apache.lucene.document.Field; 040import org.apache.lucene.document.LongPoint; 041import org.apache.lucene.document.SortedDocValuesField; 042import org.apache.lucene.util.BytesRef; 043 044public class ItemIndexer 045 extends BaseIndexer<Item> { 046 047 ItemControl itemControl = Session.getModelController(ItemControl.class); 048 049 List<ItemDescriptionType> itemDescriptionTypes; 050 SortableDescriptionProducer sortableDescriptionProducer; 051 052 /** Creates a new instance of ItemIndexer */ 053 public ItemIndexer(final ExecutionErrorAccumulator eea, final Index index) { 054 super(eea, index); 055 056 itemDescriptionTypes = itemControl.getItemDescriptionTypesByIncludeInIndex(); 057 sortableDescriptionProducer = SortableDescriptionProducerFactory.getInstance().getSortableDescriptionProducer(index.getLastDetail().getLanguage()); 058 } 059 060 @Override 061 protected Analyzer getAnalyzer() { 062 return new ItemAnalyzer(eea, language, entityType, entityAliasTypes, entityAttributes, tagScopes); 063 } 064 065 @Override 066 protected Item getEntity(final EntityInstance entityInstance) { 067 return itemControl.getItemByEntityInstance(entityInstance); 068 } 069 070 @Override 071 protected Document convertToDocument(final EntityInstance entityInstance, final Item item) { 072 var itemDetail = item.getLastDetail(); 073 var itemAliases = itemControl.getItemAliasesByItem(item); 074 var itemDeliveryType = itemDetail.getItemDeliveryType(); 075 var itemInventoryType = itemDetail.getItemInventoryType(); 076 var itemAccountingCategory = itemDetail.getItemAccountingCategory(); 077 var itemPurchasingCategory = itemDetail.getItemPurchasingCategory(); 078 var inventorySerialized = itemDetail.getInventorySerialized(); 079 var shippingEndTime = itemDetail.getShippingEndTime(); 080 var salesOrderEndTime = itemDetail.getSalesOrderEndTime(); 081 var purchaseOrderStartTime = itemDetail.getPurchaseOrderStartTime(); 082 var purchaseOrderEndTime = itemDetail.getPurchaseOrderEndTime(); 083 084 var document = newDocumentWithEntityInstanceFields(entityInstance, item.getPrimaryKey()); 085 086 document.add(new Field(IndexFields.itemName.name(), itemDetail.getItemName(), FieldTypes.NOT_STORED_TOKENIZED)); 087 document.add(new SortedDocValuesField(IndexFields.itemName.name() + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), 088 new BytesRef(itemDetail.getItemName()))); 089 document.add(new Field(IndexFields.itemNameAndAliases.name(), itemDetail.getItemName(), FieldTypes.NOT_STORED_TOKENIZED)); 090 091 document.add(new Field(IndexFields.itemTypeName.name(), itemDetail.getItemType().getItemTypeName(), FieldTypes.NOT_STORED_TOKENIZED)); 092 document.add(new Field(IndexFields.itemUseTypeName.name(), itemDetail.getItemUseType().getItemUseTypeName(), FieldTypes.NOT_STORED_TOKENIZED)); 093 094 if(itemDeliveryType != null) { 095 document.add(new Field(IndexFields.itemDeliveryTypeName.name(), itemDeliveryType.getItemDeliveryTypeName(), FieldTypes.NOT_STORED_TOKENIZED)); 096 } 097 098 if(itemInventoryType != null) { 099 document.add(new Field(IndexFields.itemInventoryTypeName.name(), itemInventoryType.getItemInventoryTypeName(), FieldTypes.NOT_STORED_TOKENIZED)); 100 } 101 102 itemAliases.stream().map((itemAlias) -> { 103 document.add(new Field(IndexFields.aliases.name(), itemAlias.getAlias(), FieldTypes.NOT_STORED_TOKENIZED)); 104 return itemAlias; 105 }).map((itemAlias) -> { 106 document.add(new Field(IndexFields.itemNameAndAliases.name(), itemAlias.getAlias(), FieldTypes.NOT_STORED_TOKENIZED)); 107 return itemAlias; 108 }).forEach((itemAlias) -> { 109 document.add(new Field(itemAlias.getItemAliasType().getLastDetail().getItemAliasTypeName(), itemAlias.getAlias(), FieldTypes.NOT_STORED_TOKENIZED)); 110 }); 111 112 document.add(new Field(IndexFields.itemCategoryName.name(), itemDetail.getItemCategory().getLastDetail().getItemCategoryName(), FieldTypes.NOT_STORED_TOKENIZED)); 113 114 if(itemAccountingCategory != null) { 115 document.add(new Field(IndexFields.itemAccountingCategoryName.name(), itemDetail.getItemAccountingCategory().getLastDetail().getItemAccountingCategoryName(), FieldTypes.NOT_STORED_TOKENIZED)); 116 } 117 118 if(itemPurchasingCategory != null) { 119 document.add(new Field(IndexFields.itemPurchasingCategoryName.name(), itemDetail.getItemPurchasingCategory().getLastDetail().getItemPurchasingCategoryName(), FieldTypes.NOT_STORED_TOKENIZED)); 120 } 121 122 if(inventorySerialized != null) { 123 document.add(new Field(IndexFields.inventorySerialized.name(), itemDetail.getInventorySerialized().toString(), FieldTypes.NOT_STORED_TOKENIZED)); 124 } 125 126 document.add(new Field(IndexFields.shippingChargeExempt.name(), itemDetail.getShippingChargeExempt().toString(), FieldTypes.NOT_STORED_TOKENIZED)); 127 document.add(new LongPoint(IndexFields.shippingStartTime.name(), itemDetail.getShippingStartTime())); 128 if(shippingEndTime != null) { 129 document.add(new LongPoint(IndexFields.shippingEndTime.name(), shippingEndTime)); 130 } 131 document.add(new LongPoint(IndexFields.salesOrderStartTime.name(), itemDetail.getSalesOrderStartTime())); 132 if(salesOrderEndTime != null) { 133 document.add(new LongPoint(IndexFields.salesOrderEndTime.name(), salesOrderEndTime)); 134 } 135 if(purchaseOrderStartTime != null) { 136 document.add(new LongPoint(IndexFields.purchaseOrderStartTime.name(), purchaseOrderStartTime)); 137 } 138 if(purchaseOrderEndTime != null) { 139 document.add(new LongPoint(IndexFields.purchaseOrderEndTime.name(), purchaseOrderEndTime)); 140 } 141 document.add(new Field(IndexFields.allowClubDiscounts.name(), itemDetail.getAllowClubDiscounts().toString(), FieldTypes.NOT_STORED_TOKENIZED)); 142 document.add(new Field(IndexFields.allowCouponDiscounts.name(), itemDetail.getAllowCouponDiscounts().toString(), FieldTypes.NOT_STORED_TOKENIZED)); 143 document.add(new Field(IndexFields.allowAssociatePayments.name(), itemDetail.getAllowAssociatePayments().toString(), FieldTypes.NOT_STORED_TOKENIZED)); 144 145 document.add(new Field(IndexFields.unitOfMeasureKindName.name(), itemDetail.getUnitOfMeasureKind().getLastDetail().getUnitOfMeasureKindName(), FieldTypes.NOT_STORED_TOKENIZED)); 146 document.add(new Field(IndexFields.itemPriceTypeName.name(), itemDetail.getItemPriceType().getItemPriceTypeName(), FieldTypes.NOT_STORED_TOKENIZED)); 147 148 itemDescriptionTypes.forEach((itemDescriptionType) -> { 149 var itemDescription = itemControl.getBestItemDescription(itemDescriptionType, item, language); 150 if (itemDescription != null) { 151 var itemDescriptionTypeDetail = itemDescriptionType.getLastDetail(); 152 var mimeTypeUsageType = itemDescriptionTypeDetail.getMimeTypeUsageType(); 153 var itemDescriptionTypeName = itemDescriptionTypeDetail.getItemDescriptionTypeName(); 154 155 if(mimeTypeUsageType == null) { 156 var itemStringDescription = itemControl.getItemStringDescription(itemDescription); 157 var stringDescription = itemStringDescription.getStringDescription(); 158 159 document.add(new Field(itemDescriptionTypeName, stringDescription, FieldTypes.NOT_STORED_TOKENIZED)); 160 document.add(new Field(itemDescriptionTypeName + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.dictionary.name(), 161 stringDescription, FieldTypes.NOT_STORED_TOKENIZED)); 162 document.add(new SortedDocValuesField(itemDescriptionTypeName + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), 163 new BytesRef(sortableDescriptionProducer.getSortableDescription(stringDescription)))); 164 165 if(IndexerDebugFlags.LogItemIndexing) { 166 log.info("--- " + itemDescriptionTypeName + ", stringDescription = " + stringDescription); 167 } 168 } else { 169 var mimeTypeUsageTypeName = mimeTypeUsageType.getMimeTypeUsageTypeName(); 170 171 if(mimeTypeUsageTypeName.equals(MimeTypeUsageTypes.TEXT.name())) { 172 var itemClobDescription = itemControl.getItemClobDescription(itemDescription); 173 var clobDescription = itemClobDescription.getClobDescription(); 174 175 // TODO: mime type conversion to text/plain happens here 176 document.add(new Field(itemDescriptionTypeName, clobDescription, FieldTypes.NOT_STORED_TOKENIZED)); 177 178 if(IndexerDebugFlags.LogItemIndexing) { 179 log.info("--- " + itemDescriptionTypeName + ", clobDescription = " + clobDescription); 180 } 181 } // Others are not supported at this time, DOCUMENT probably should be. 182 } 183 } 184 }); 185 186 return document; 187 } 188 189}