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