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