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