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.contact.server.indexer;
018
019import com.echothree.model.control.contact.common.ContactMechanismTypes;
020import com.echothree.model.control.contact.server.control.ContactControl;
021import com.echothree.model.control.geo.server.control.GeoControl;
022import com.echothree.model.control.index.common.IndexConstants;
023import com.echothree.model.control.index.common.IndexFieldVariations;
024import com.echothree.model.control.index.common.IndexFields;
025import com.echothree.model.control.index.server.analysis.ContactMechanismAnalyzer;
026import com.echothree.model.control.index.server.indexer.BaseIndexer;
027import com.echothree.model.control.index.server.indexer.FieldTypes;
028import com.echothree.model.data.contact.server.entity.ContactEmailAddress;
029import com.echothree.model.data.contact.server.entity.ContactInet4Address;
030import com.echothree.model.data.contact.server.entity.ContactMechanism;
031import com.echothree.model.data.contact.server.entity.ContactMechanismDetail;
032import com.echothree.model.data.contact.server.entity.ContactMechanismPurpose;
033import com.echothree.model.data.contact.server.entity.ContactPostalAddress;
034import com.echothree.model.data.contact.server.entity.ContactTelephone;
035import com.echothree.model.data.contact.server.entity.ContactWebAddress;
036import com.echothree.model.data.contact.server.entity.PartyContactMechanismDetail;
037import com.echothree.model.data.core.server.entity.EntityInstance;
038import com.echothree.model.data.geo.server.entity.GeoCode;
039import com.echothree.model.data.index.server.entity.Index;
040import com.echothree.model.data.party.server.entity.Language;
041import com.echothree.model.data.party.server.entity.NameSuffix;
042import com.echothree.model.data.party.server.entity.Party;
043import com.echothree.model.data.party.server.entity.PartyType;
044import com.echothree.model.data.party.server.entity.PersonalTitle;
045import com.echothree.util.common.string.Inet4AddressUtils;
046import com.echothree.util.server.message.ExecutionErrorAccumulator;
047import com.echothree.util.server.persistence.Session;
048import java.util.HashSet;
049import java.util.Set;
050import org.apache.lucene.analysis.Analyzer;
051import org.apache.lucene.document.Document;
052import org.apache.lucene.document.Field;
053import org.apache.lucene.document.SortedDocValuesField;
054import org.apache.lucene.util.BytesRef;
055
056public class ContactMechanismIndexer
057        extends BaseIndexer<ContactMechanism> {
058    
059    ContactControl contactControl = Session.getModelController(ContactControl.class);
060    GeoControl geoControl = Session.getModelController(GeoControl.class);
061
062    /** Creates a new instance of ContactMechanismIndexer */
063    public ContactMechanismIndexer(final ExecutionErrorAccumulator eea, final Index index) {
064        super(eea, index);
065    }
066
067    @Override
068    protected Analyzer getAnalyzer() {
069        return new ContactMechanismAnalyzer(eea, language, entityType, entityAliasTypes, entityAttributes, tagScopes);
070    }
071    
072    @Override
073    protected ContactMechanism getEntity(final EntityInstance entityInstance) {
074        return contactControl.getContactMechanismByEntityInstance(entityInstance);
075    }
076    
077    private void addPartyNamesToDocument(Document document, Set<Party> parties) {
078        StringBuilder partyNamesBuilder = new StringBuilder();
079
080        parties.forEach((party) -> {
081            if(partyNamesBuilder.length() != 0) {
082                partyNamesBuilder.append(' ');
083            }
084
085            partyNamesBuilder.append(party.getLastDetail().getPartyName());
086        });
087
088        document.add(new Field(IndexFields.partyNames.name(), partyNamesBuilder.toString(), FieldTypes.NOT_STORED_TOKENIZED));
089    }
090    
091    private void addPartyTypeNamesToDocument(Document document, Set<PartyType> partyTypes) {
092        StringBuilder partyTypeNamesBuilder = new StringBuilder();
093
094        partyTypes.forEach((partyType) -> {
095            if(partyTypeNamesBuilder.length() != 0) {
096                partyTypeNamesBuilder.append(' ');
097            }
098
099            partyTypeNamesBuilder.append(partyType.getPartyTypeName());
100        });
101
102        document.add(new Field(IndexFields.partyTypeNames.name(), partyTypeNamesBuilder.toString(), FieldTypes.NOT_STORED_TOKENIZED));
103    }
104    
105    private void addContactMechanismPurposeNamesToDocument(Document document, Set<ContactMechanismPurpose> contactMechanismPurposes) {
106        StringBuilder contactMechanismPurposesNamesBuilder = new StringBuilder();
107
108        contactMechanismPurposes.forEach((contactMechanismPurpose) -> {
109            if(contactMechanismPurposesNamesBuilder.length() != 0) {
110                contactMechanismPurposesNamesBuilder.append(' ');
111            }
112
113            contactMechanismPurposesNamesBuilder.append(contactMechanismPurpose.getContactMechanismPurposeName());
114        });
115
116        document.add(new Field(IndexFields.contactMechanismPurposeNames.name(), contactMechanismPurposesNamesBuilder.toString(), FieldTypes.NOT_STORED_TOKENIZED));
117    }
118    
119    private void addPartiesToDocument(final Document document, final ContactMechanism contactMechanism) {
120        Set<Party> parties = new HashSet<>();
121        Set<PartyType> partyTypes = new HashSet<>();
122        Set<ContactMechanismPurpose> contactMechanismPurposes = new HashSet<>();
123        
124        contactControl.getPartyContactMechanismsByContactMechanism(contactMechanism).stream().forEach((partyContactMechanism) -> {
125            PartyContactMechanismDetail partyContactMechanismDetail = partyContactMechanism.getLastDetail();
126            Party party = partyContactMechanismDetail.getParty();
127            parties.add(party);
128            partyTypes.add(party.getLastDetail().getPartyType());
129            contactControl.getPartyContactMechanismPurposesByPartyContactMechanism(partyContactMechanism).stream().forEach((partyContactMechanismPurpose) -> {
130                contactMechanismPurposes.add(partyContactMechanismPurpose.getLastDetail().getContactMechanismPurpose());
131            });
132        });
133        
134        addPartyNamesToDocument(document, parties);
135        addPartyTypeNamesToDocument(document, partyTypes);
136        addContactMechanismPurposeNamesToDocument(document, contactMechanismPurposes);
137    }
138    
139    private void addGeoCodeToDocument(final Document document, final Language language, final GeoCode geoCode, String description, final String geoCodeIndexField, final String descriptionIndexField) {
140        if(geoCode != null) {
141            description = geoControl.getBestGeoCodeDescription(geoCode, language);
142
143            document.add(new Field(geoCodeIndexField, geoCode.getLastDetail().getGeoCodeName(), FieldTypes.NOT_STORED_TOKENIZED));
144        }
145
146        if(description != null) {
147            document.add(new Field(descriptionIndexField, description, FieldTypes.NOT_STORED_TOKENIZED));
148        }
149    }
150    
151    private void addContactEmailAddressToDocument(final Document document, final ContactMechanism contactMechanism) {
152        ContactEmailAddress contactEmailAddress = contactControl.getContactEmailAddress(contactMechanism);
153
154        if(contactEmailAddress != null) {
155            document.add(new Field(IndexFields.emailAddress.name(), contactEmailAddress.getEmailAddress(), FieldTypes.NOT_STORED_TOKENIZED));
156        }
157    }
158
159    private void addContactInet4AddressToDocument(final Document document, final ContactMechanism contactMechanism) {
160        ContactInet4Address contactInet4Address = contactControl.getContactInet4Address(contactMechanism);
161
162        if(contactInet4Address != null) {
163            document.add(new Field(IndexFields.inet4Address.name(), Inet4AddressUtils.getInstance().formatInet4Address(contactInet4Address.getInet4Address()), FieldTypes.NOT_STORED_TOKENIZED));
164        }
165    }
166
167    private void addContactPostalAddressToDocument(final Document document, final ContactMechanism contactMechanism, final Language language) {
168        ContactPostalAddress contactPostalAddress = contactControl.getContactPostalAddress(contactMechanism);
169
170        if(contactPostalAddress != null) {
171            PersonalTitle personalTitle = contactPostalAddress.getPersonalTitle();
172            String firstName = contactPostalAddress.getFirstName();
173            String middleName = contactPostalAddress.getMiddleName();
174            String lastName = contactPostalAddress.getLastName();
175            NameSuffix nameSuffix = contactPostalAddress.getNameSuffix();
176            String companyName = contactPostalAddress.getCompanyName();
177            String attention = contactPostalAddress.getAttention();
178            String address2 = contactPostalAddress.getAddress2();
179            String address3 = contactPostalAddress.getAddress3();
180
181            if(personalTitle != null) {
182                document.add(new Field(IndexFields.personalTitle.name(), personalTitle.getLastDetail().getDescription(), FieldTypes.NOT_STORED_TOKENIZED));
183            }
184
185            if(firstName != null) {
186                document.add(new Field(IndexFields.firstName.name(), firstName, FieldTypes.NOT_STORED_TOKENIZED));
187            }
188
189            if(middleName != null) {
190                document.add(new Field(IndexFields.middleName.name(), middleName, FieldTypes.NOT_STORED_TOKENIZED));
191            }
192
193            if(lastName != null) {
194                document.add(new Field(IndexFields.lastName.name(), lastName, FieldTypes.NOT_STORED_TOKENIZED));
195            }
196
197            if(nameSuffix != null) {
198                document.add(new Field(IndexFields.nameSuffix.name(), nameSuffix.getLastDetail().getDescription(), FieldTypes.NOT_STORED_TOKENIZED));
199            }
200
201            if(companyName != null) {
202                document.add(new Field(IndexFields.companyName.name(), companyName, FieldTypes.NOT_STORED_TOKENIZED));
203            }
204
205            if(attention != null) {
206                document.add(new Field(IndexFields.attention.name(), attention, FieldTypes.NOT_STORED_TOKENIZED));
207            }
208
209            document.add(new Field(IndexFields.address1.name(), contactPostalAddress.getAddress1(), FieldTypes.NOT_STORED_TOKENIZED));
210
211            if(address2 != null) {
212                document.add(new Field(IndexFields.address2.name(), address2, FieldTypes.NOT_STORED_TOKENIZED));
213            }
214
215            if(address3 != null) {
216                document.add(new Field(IndexFields.address3.name(), address3, FieldTypes.NOT_STORED_TOKENIZED));
217            }
218
219            addGeoCodeToDocument(document, language, contactPostalAddress.getCityGeoCode(), contactPostalAddress.getCity(), IndexFields.cityGeoCodeName.name(), IndexFields.city.name());
220            addGeoCodeToDocument(document, language, contactPostalAddress.getCountyGeoCode(), null, IndexFields.countyGeoCodeName.name(), IndexFields.county.name());
221            addGeoCodeToDocument(document, language, contactPostalAddress.getStateGeoCode(), contactPostalAddress.getState(), IndexFields.stateGeoCodeName.name(), IndexFields.state.name());
222            addGeoCodeToDocument(document, language, contactPostalAddress.getPostalCodeGeoCode(), contactPostalAddress.getPostalCode(), IndexFields.postalCodeGeoCodeName.name(), IndexFields.postalCode.name());
223            addGeoCodeToDocument(document, language, contactPostalAddress.getCountryGeoCode(), null, IndexFields.countryGeoCodeName.name(), IndexFields.country.name());
224
225            document.add(new Field(IndexFields.isCommercial.name(), contactPostalAddress.getIsCommercial().toString(), FieldTypes.NOT_STORED_TOKENIZED));
226        }
227    }
228
229    private void addContactTelephoneToDocument(final Document document, final ContactMechanism contactMechanism) {
230        ContactTelephone contactTelephone = contactControl.getContactTelephone(contactMechanism);
231
232        if(contactTelephone != null) {
233            String areaCode = contactTelephone.getAreaCode();
234            String telephoneExtension = contactTelephone.getTelephoneExtension();
235
236            document.add(new Field(IndexFields.countryGeoCodeName.name(), contactTelephone.getCountryGeoCode().getLastDetail().getGeoCodeName(), FieldTypes.NOT_STORED_TOKENIZED));
237
238            if(areaCode != null) {
239                document.add(new Field(IndexFields.areaCode.name(), areaCode, FieldTypes.NOT_STORED_TOKENIZED));
240            }
241
242            document.add(new Field(IndexFields.telephoneNumber.name(), contactTelephone.getTelephoneNumber(), FieldTypes.NOT_STORED_TOKENIZED));
243
244            if(telephoneExtension != null) {
245                document.add(new Field(IndexFields.telephoneExtension.name(), telephoneExtension, FieldTypes.NOT_STORED_TOKENIZED));
246            }
247        }
248    }
249
250    private void addContactWebAddressToDocument(final Document document, final ContactMechanism contactMechanism) {
251        ContactWebAddress contactWebAddress = contactControl.getContactWebAddress(contactMechanism);
252
253        if(contactWebAddress != null) {
254            document.add(new Field(IndexFields.url.name(), contactWebAddress.getUrl(), FieldTypes.NOT_STORED_TOKENIZED));
255        }
256    }
257    
258    private void addContactMechanismToDocument(final Document document, final ContactMechanism contactMechanism, final Language language) {
259        ContactMechanismDetail contactMechanismDetail = contactMechanism.getLastDetail();
260        String contactMechanismTypeName = contactMechanismDetail.getContactMechanismType().getContactMechanismTypeName();
261        
262        document.add(new Field(IndexFields.contactMechanismName.name(), contactMechanismDetail.getContactMechanismName(), FieldTypes.NOT_STORED_TOKENIZED));
263        document.add(new SortedDocValuesField(IndexFields.contactMechanismName.name() + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(),
264                new BytesRef(contactMechanismDetail.getContactMechanismName())));
265
266        document.add(new Field(IndexFields.contactMechanismTypeName.name(), contactMechanismTypeName, FieldTypes.NOT_STORED_TOKENIZED));
267        document.add(new Field(IndexFields.allowSolicitation.name(), contactMechanismDetail.getAllowSolicitation().toString(), FieldTypes.NOT_STORED_TOKENIZED));
268        
269        if(contactMechanismTypeName.equals(ContactMechanismTypes.EMAIL_ADDRESS.name())) {
270            addContactEmailAddressToDocument(document, contactMechanism);
271        } else if(contactMechanismTypeName.equals(ContactMechanismTypes.INET_4.name())) {
272            addContactInet4AddressToDocument(document, contactMechanism);
273        } else if(contactMechanismTypeName.equals(ContactMechanismTypes.INET_6.name())) {
274            // TODO
275        } else if(contactMechanismTypeName.equals(ContactMechanismTypes.POSTAL_ADDRESS.name())) {
276            addContactPostalAddressToDocument(document, contactMechanism, language);
277        } else if(contactMechanismTypeName.equals(ContactMechanismTypes.TELECOM_ADDRESS.name())) {
278            addContactTelephoneToDocument(document, contactMechanism);
279        } else if(contactMechanismTypeName.equals(ContactMechanismTypes.WEB_ADDRESS.name())) {
280            addContactWebAddressToDocument(document, contactMechanism);
281        }
282    }
283    
284    @Override
285    protected Document convertToDocument(final EntityInstance entityInstance, final ContactMechanism contactMechanism) {
286        var document = newDocumentWithEntityInstanceFields(entityInstance, contactMechanism.getPrimaryKey());
287
288        addPartiesToDocument(document, contactMechanism);
289        addContactMechanismToDocument(document, contactMechanism, language);
290
291        return document;
292    }
293
294}