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.control.user.search.server.command;
018
019import com.echothree.control.user.search.common.form.IdentifyForm;
020import com.echothree.control.user.search.common.result.SearchResultFactory;
021import com.echothree.model.control.core.common.CoreOptions;
022import com.echothree.model.control.core.common.CoreProperties;
023import com.echothree.model.control.core.common.transfer.ComponentVendorTransfer;
024import com.echothree.model.control.core.common.transfer.EntityInstanceTransfer;
025import com.echothree.model.control.core.common.transfer.EntityTypeTransfer;
026import com.echothree.model.control.core.server.control.EntityAliasControl;
027import com.echothree.model.control.core.server.control.EntityInstanceControl;
028import com.echothree.model.control.core.server.search.ComponentVendorSearchEvaluator;
029import com.echothree.model.control.core.server.search.EntityAliasTypeSearchEvaluator;
030import com.echothree.model.control.core.server.search.EntityAttributeGroupSearchEvaluator;
031import com.echothree.model.control.core.server.search.EntityAttributeSearchEvaluator;
032import com.echothree.model.control.core.server.search.EntityListItemSearchEvaluator;
033import com.echothree.model.control.core.server.search.EntityTypeSearchEvaluator;
034import com.echothree.model.control.customer.server.control.CustomerControl;
035import com.echothree.model.control.customer.server.search.CustomerSearchEvaluator;
036import com.echothree.model.control.employee.server.control.EmployeeControl;
037import com.echothree.model.control.employee.server.search.EmployeeSearchEvaluator;
038import com.echothree.model.control.item.server.control.ItemControl;
039import com.echothree.model.control.item.server.search.ItemSearchEvaluator;
040import com.echothree.model.control.party.server.control.PartyControl;
041import com.echothree.model.control.search.common.SearchKinds;
042import com.echothree.model.control.search.common.SearchTypes;
043import com.echothree.model.control.search.server.control.SearchControl;
044import com.echothree.model.control.search.server.logic.SearchLogic;
045import com.echothree.model.control.security.common.SecurityRoleGroups;
046import com.echothree.model.control.security.common.SecurityRoles;
047import com.echothree.model.control.vendor.server.control.VendorControl;
048import com.echothree.model.control.vendor.server.search.VendorSearchEvaluator;
049import com.echothree.model.control.warehouse.server.control.WarehouseControl;
050import com.echothree.model.control.warehouse.server.search.WarehouseSearchEvaluator;
051import com.echothree.model.data.party.server.entity.Party;
052import com.echothree.model.data.search.server.entity.SearchKind;
053import com.echothree.model.data.search.server.entity.SearchType;
054import com.echothree.model.data.user.server.entity.UserVisit;
055import com.echothree.util.common.command.BaseResult;
056import com.echothree.util.common.string.NameResult;
057import com.echothree.util.common.validation.FieldDefinition;
058import com.echothree.util.common.validation.FieldType;
059import com.echothree.util.server.control.BaseSimpleCommand;
060import com.echothree.util.server.message.DummyExecutionErrorAccumulator;
061import com.echothree.util.server.persistence.EntityNamesUtils;
062import com.echothree.util.server.persistence.translator.EntityInstanceAndNames;
063import com.echothree.util.server.string.NameCleaner;
064import com.echothree.util.server.validation.fieldtype.EntityNameFieldType;
065import java.util.HashSet;
066import java.util.List;
067import java.util.Set;
068import javax.enterprise.context.Dependent;
069import javax.inject.Inject;
070
071@Dependent
072public class IdentifyCommand
073        extends BaseSimpleCommand<IdentifyForm> {
074    
075    private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS;
076    
077    static {
078        FORM_FIELD_DEFINITIONS = List.of(
079                new FieldDefinition("Target", FieldType.STRING, true, null, null)
080        );
081    }
082
083    @Inject
084    CustomerControl customerControl;
085
086    @Inject
087    EmployeeControl employeeControl;
088
089    @Inject
090    EntityAliasControl entityAliasControl;
091
092    @Inject
093    EntityInstanceControl entityInstanceControl;
094
095    @Inject
096    ItemControl itemControl;
097
098    @Inject
099    PartyControl partyControl;
100
101    @Inject
102    SearchControl searchControl;
103
104    @Inject
105    VendorControl vendorControl;
106
107    @Inject
108    WarehouseControl warehouseControl;
109
110    @Inject
111    SearchLogic searchLogic;
112
113    
114    /** Creates a new instance of IdentifyCommand */
115    public IdentifyCommand() {
116        super(null, FORM_FIELD_DEFINITIONS, true);
117    }
118
119    @Override
120    protected void setupSession() {
121        super.setupSession();
122
123        // Names are always included in the JumpResult, assembly of them is a little weird, so always disallow this option.
124        removeOption(CoreOptions.EntityInstanceIncludeNames);
125
126        // Ensure we're able to compare instances of and generate a HashCode for the EntityInstanceTransfers
127        removeFilteredTransferProperty(EntityInstanceTransfer.class, CoreProperties.ENTITY_TYPE);
128        removeFilteredTransferProperty(EntityTypeTransfer.class, CoreProperties.COMPONENT_VENDOR);
129        removeFilteredTransferProperty(EntityTypeTransfer.class, CoreProperties.ENTITY_TYPE_NAME);
130        removeFilteredTransferProperty(ComponentVendorTransfer.class, CoreProperties.COMPONENT_VENDOR_NAME);
131    }
132    
133    private EntityInstanceTransfer fillInEntityInstance(EntityInstanceAndNames entityInstanceAndNames) {
134        var entityInstance = entityInstanceControl.getEntityInstanceTransfer(getUserVisit(), entityInstanceAndNames.getEntityInstance(), false, false, false, false);
135
136        entityInstance.setEntityNames(entityInstanceAndNames.getEntityNames());
137        
138        return entityInstance;
139    }
140    
141    private void checkSequenceTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
142        var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(this, party, target, true);
143        
144        if(entityInstanceAndNames != null) {
145            entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
146        }
147    }
148    
149    private void checkItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
150        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
151                SecurityRoleGroups.Item.name(), SecurityRoles.Search.name())) {
152            var item = itemControl.getItemByNameThenAlias(target);
153
154            if(item != null) {
155                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(item.getPrimaryKey());
156                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
157
158                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
159            }
160        }
161    }
162
163    private void checkCompanies(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
164        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
165                SecurityRoleGroups.Company.name(), SecurityRoles.Search.name())) {
166            var partyCompany = partyControl.getPartyCompanyByName(target);
167
168            if(partyCompany != null) {
169                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyCompany.getParty().getPrimaryKey());
170                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
171
172                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
173            }
174        }
175    }
176
177    private void checkDivisions(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
178        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
179                SecurityRoleGroups.Division.name(), SecurityRoles.Search.name())) {
180            var partyDivisions = partyControl.getDivisionsByName(target);
181
182            partyDivisions.stream().map((partyDivision) -> entityInstanceControl.getEntityInstanceByBasePK(partyDivision.getParty().getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
183                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
184            });
185        }
186    }
187
188    private void checkDepartments(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
189        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
190                SecurityRoleGroups.Department.name(), SecurityRoles.Search.name())) {
191            var partyDepartments = partyControl.getDepartmentsByName(target);
192
193            partyDepartments.stream().map((partyDepartment) -> entityInstanceControl.getEntityInstanceByBasePK(partyDepartment.getParty().getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
194                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
195            });
196        }
197    }
198
199    private void checkWarehouses(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
200        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
201                SecurityRoleGroups.Warehouse.name(), SecurityRoles.Search.name())) {
202            var warehouse = warehouseControl.getWarehouseByName(target);
203
204            if(warehouse != null) {
205                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(warehouse.getParty().getPrimaryKey());
206                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
207
208                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
209            }
210        }
211    }
212
213    private void checkLocations(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
214        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
215                SecurityRoleGroups.Location.name(), SecurityRoles.Search.name())) {
216            var locations = warehouseControl.getLocationsByName(target);
217
218            locations.stream().map((location) -> entityInstanceControl.getEntityInstanceByBasePK(location.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
219                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
220            });
221        }
222    }
223
224    private void checkEmployees(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
225        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
226                SecurityRoleGroups.Employee.name(), SecurityRoles.Search.name())) {
227            var partyEmployee = employeeControl.getPartyEmployeeByName(target);
228
229            if(partyEmployee != null) {
230                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyEmployee.getParty().getPrimaryKey());
231                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
232
233                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
234            }
235        }
236    }
237
238    private void checkCustomers(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
239        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
240                SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name())) {
241            var customer = customerControl.getCustomerByName(target);
242
243            if(customer != null) {
244                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(customer.getParty().getPrimaryKey());
245                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
246
247                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
248            }
249        }
250    }
251
252    private void checkVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
253        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
254                SecurityRoleGroups.Vendor.name(), SecurityRoles.Search.name())) {
255            var vendor = vendorControl.getVendorByName(target);
256
257            if(vendor != null) {
258                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(vendor.getParty().getPrimaryKey());
259                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
260
261                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
262            }
263        }
264    }
265
266    private void checkVendorItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
267        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
268                SecurityRoleGroups.VendorItem.name(), SecurityRoles.Search.name())) {
269            var vendorItems = vendorControl.getVendorItemsByVendorItemName(target);
270
271            vendorItems.stream().map((vendorItem) -> entityInstanceControl.getEntityInstanceByBasePK(vendorItem.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
272                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
273            });
274        }
275    }
276
277    private void checkComponentVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
278        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
279                SecurityRoleGroups.ComponentVendor.name(), SecurityRoles.Search.name())) {
280            var componentVendor = componentControl.getComponentVendorByName(target);
281
282            if(componentVendor != null) {
283                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(componentVendor.getPrimaryKey());
284                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
285
286                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
287            }
288        }
289    }
290
291    private void checkEntityTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
292        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
293                SecurityRoleGroups.EntityType.name(), SecurityRoles.Search.name())) {
294            var entityTypes = entityTypeControl.getEntityTypesByName(target);
295
296            entityTypes.stream().map((entityType) -> entityInstanceControl.getEntityInstanceByBasePK(entityType.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
297                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
298            });
299        }
300    }
301
302    private void checkEntityAliasTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
303        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
304                SecurityRoleGroups.EntityAliasType.name(), SecurityRoles.Search.name())) {
305            var entityAliasTypes = entityAliasControl.getEntityAliasTypesByName(target);
306
307            entityAliasTypes.stream().map((entityAliasType) -> entityInstanceControl.getEntityInstanceByBasePK(entityAliasType.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
308                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
309            });
310        }
311    }
312
313    private void checkEntityAttributes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
314        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
315                SecurityRoleGroups.EntityAttribute.name(), SecurityRoles.Search.name())) {
316            var entityAttributes = coreControl.getEntityAttributesByName(target);
317
318            entityAttributes.stream().map((entityAttribute) -> entityInstanceControl.getEntityInstanceByBasePK(entityAttribute.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
319                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
320            });
321        }
322    }
323
324    private void checkEntityListItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
325        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
326                SecurityRoleGroups.EntityListItem.name(), SecurityRoles.Search.name())) {
327            var entityListItems = coreControl.getEntityListItemsByName(target);
328
329            entityListItems.stream().map((entityListItem) -> entityInstanceControl.getEntityInstanceByBasePK(entityListItem.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
330                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
331            });
332        }
333    }
334
335    private void checkEntityAttributeGroups(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
336        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
337                SecurityRoleGroups.EntityAttributeGroup.name(), SecurityRoles.Search.name())) {
338            var entityAttributeGroup = coreControl.getEntityAttributeGroupByName(target);
339
340            if(entityAttributeGroup != null) {
341                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(entityAttributeGroup.getPrimaryKey());
342                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
343
344                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
345            }
346        }
347    }
348
349    private void executeCustomerSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
350            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
351            final String firstName, final String middleName, final String lastName, final String q) {
352        var customerSearchEvaluator = new CustomerSearchEvaluator(userVisit, searchType,
353                searchLogic.getDefaultSearchDefaultOperator(null),
354                searchLogic.getDefaultSearchSortOrder(null, searchKind),
355                searchLogic.getDefaultSearchSortDirection(null));
356
357        customerSearchEvaluator.setFirstName(firstName);
358        customerSearchEvaluator.setFirstNameSoundex(false);
359        customerSearchEvaluator.setMiddleName(middleName);
360        customerSearchEvaluator.setMiddleNameSoundex(false);
361        customerSearchEvaluator.setLastName(lastName);
362        customerSearchEvaluator.setLastNameSoundex(false);
363        customerSearchEvaluator.setQ(null, q);
364
365        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
366        // accumulating errors for this UC.
367        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
368        customerSearchEvaluator.execute(dummyExecutionErrorAccumulator);
369
370        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
371            addSearchResults(userVisit, searchType, entityInstances);
372        }
373    }
374
375    private void searchCustomers(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
376            final NameResult nameResult) {
377        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
378                SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name())) {
379            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.CUSTOMER.name());
380
381            if(!hasExecutionErrors()) {
382                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
383
384                if(!hasExecutionErrors()) {
385                    var userVisit = getUserVisit();
386
387                    // First attempt using a first and/or last name isolated from target.
388                    executeCustomerSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
389                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
390                    // Then attempt searching for target using it as a query string.
391                    executeCustomerSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
392                            null, null, null, target);
393                }
394            }
395        }
396    }
397
398    private void executeEmployeeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
399            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
400            final String firstName, final String middleName, final String lastName, final String q) {
401        var employeeSearchEvaluator = new EmployeeSearchEvaluator(userVisit, searchType,
402                searchLogic.getDefaultSearchDefaultOperator(null),
403                searchLogic.getDefaultSearchSortOrder(null, searchKind),
404                searchLogic.getDefaultSearchSortDirection(null));
405
406        employeeSearchEvaluator.setFirstName(firstName);
407        employeeSearchEvaluator.setFirstNameSoundex(false);
408        employeeSearchEvaluator.setMiddleName(middleName);
409        employeeSearchEvaluator.setMiddleNameSoundex(false);
410        employeeSearchEvaluator.setLastName(lastName);
411        employeeSearchEvaluator.setLastNameSoundex(false);
412        employeeSearchEvaluator.setQ(null, q);
413
414        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
415        // accumulating errors for this UC.
416        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
417        employeeSearchEvaluator.execute(dummyExecutionErrorAccumulator);
418
419        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
420            addSearchResults(userVisit, searchType, entityInstances);
421        }
422    }
423
424    private void searchEmployees(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
425            final NameResult nameResult) {
426        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
427                SecurityRoleGroups.Employee.name(), SecurityRoles.Search.name())) {
428            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.EMPLOYEE.name());
429
430            if(!hasExecutionErrors()) {
431                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
432
433                if(!hasExecutionErrors()) {
434                    var userVisit = getUserVisit();
435
436                    // First attempt using a first and/or last name isolated from target.
437                    executeEmployeeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
438                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
439                    // Then attempt searching for target using it as a query string.
440                    executeEmployeeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
441                            null, null, null, target);
442                }
443            }
444        }
445    }
446
447    private void executeVendorSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
448            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
449            final String firstName, final String middleName, final String lastName, final String q) {
450        var vendorSearchEvaluator = new VendorSearchEvaluator(userVisit, searchType,
451                searchLogic.getDefaultSearchDefaultOperator(null),
452                searchLogic.getDefaultSearchSortOrder(null, searchKind),
453                searchLogic.getDefaultSearchSortDirection(null));
454
455        vendorSearchEvaluator.setFirstName(firstName);
456        vendorSearchEvaluator.setFirstNameSoundex(false);
457        vendorSearchEvaluator.setMiddleName(middleName);
458        vendorSearchEvaluator.setMiddleNameSoundex(false);
459        vendorSearchEvaluator.setLastName(lastName);
460        vendorSearchEvaluator.setLastNameSoundex(false);
461        vendorSearchEvaluator.setQ(null, q);
462
463        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
464        // accumulating errors for this UC.
465        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
466        vendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
467
468        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
469            addSearchResults(userVisit, searchType, entityInstances);
470        }
471    }
472
473    private void searchVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
474            final NameResult nameResult) {
475        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
476                SecurityRoleGroups.Vendor.name(), SecurityRoles.Search.name())) {
477            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.VENDOR.name());
478
479            if(!hasExecutionErrors()) {
480                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
481
482                if(!hasExecutionErrors()) {
483                    var userVisit = getUserVisit();
484
485                    // First attempt using a first and/or last name isolated from target.
486                    executeVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
487                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
488                    // Then attempt searching for target using it as a query string.
489                    executeVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
490                            null, null, null, target);
491                }
492            }
493        }
494    }
495
496    private void executeWarehouseSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
497            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType, final String q) {
498        var warehouseSearchEvaluator = new WarehouseSearchEvaluator(userVisit, searchType,
499                searchLogic.getDefaultSearchDefaultOperator(null),
500                searchLogic.getDefaultSearchSortOrder(null, searchKind),
501                searchLogic.getDefaultSearchSortDirection(null));
502
503        warehouseSearchEvaluator.setQ(null, q);
504
505        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
506        // accumulating errors for this UC.
507        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
508        warehouseSearchEvaluator.execute(dummyExecutionErrorAccumulator);
509
510        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
511            addSearchResults(userVisit, searchType, entityInstances);
512        }
513    }
514
515    private void searchWarehouses(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
516        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
517                SecurityRoleGroups.Warehouse.name(), SecurityRoles.Search.name())) {
518            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.WAREHOUSE.name());
519
520            if(!hasExecutionErrors()) {
521                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
522
523                if(!hasExecutionErrors()) {
524                    var userVisit = getUserVisit();
525
526                    // Attempt searching for target using it as a query string.
527                    executeWarehouseSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
528                            target);
529                }
530            }
531        }
532    }
533
534    private void executeItemSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
535            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
536            final String q) {
537        var itemSearchEvaluator = new ItemSearchEvaluator(userVisit, null, searchType,
538                searchLogic.getDefaultSearchDefaultOperator(null),
539                searchLogic.getDefaultSearchSortOrder(null, searchKind),
540                searchLogic.getDefaultSearchSortDirection(null),
541                null);
542
543        itemSearchEvaluator.setQ(null, q);
544
545        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
546        // accumulating errors for this UC.
547        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
548        itemSearchEvaluator.execute(dummyExecutionErrorAccumulator);
549
550        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
551            addSearchResults(userVisit, searchType, entityInstances);
552        }
553    }
554
555    private void searchItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
556        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
557                SecurityRoleGroups.Item.name(), SecurityRoles.Search.name())) {
558            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ITEM.name());
559
560            if(!hasExecutionErrors()) {
561                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
562
563                if(!hasExecutionErrors()) {
564                    var userVisit = getUserVisit();
565
566                    executeItemSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
567                }
568            }
569        }
570    }
571
572    private void executeComponentVendorSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
573            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
574            final String q) {
575        var componentVendorSearchEvaluator = new ComponentVendorSearchEvaluator(userVisit, null, searchType,
576                searchLogic.getDefaultSearchDefaultOperator(null),
577                searchLogic.getDefaultSearchSortOrder(null, searchKind),
578                searchLogic.getDefaultSearchSortDirection(null),
579                null);
580
581        componentVendorSearchEvaluator.setQ(null, q);
582
583        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
584        // accumulating errors for this UC.
585        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
586        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
587
588        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
589            addSearchResults(userVisit, searchType, entityInstances);
590        }
591    }
592
593    private void searchComponentVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
594        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
595                SecurityRoleGroups.ComponentVendor.name(), SecurityRoles.Search.name())) {
596            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.COMPONENT_VENDOR.name());
597
598            if(!hasExecutionErrors()) {
599                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
600
601                if(!hasExecutionErrors()) {
602                    var userVisit = getUserVisit();
603
604                    executeComponentVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
605                }
606            }
607        }
608    }
609
610    private void executeEntityTypeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
611            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
612            final String q) {
613        var componentVendorSearchEvaluator = new EntityTypeSearchEvaluator(userVisit, null, searchType,
614                searchLogic.getDefaultSearchDefaultOperator(null),
615                searchLogic.getDefaultSearchSortOrder(null, searchKind),
616                searchLogic.getDefaultSearchSortDirection(null),
617                null);
618
619        componentVendorSearchEvaluator.setQ(null, q);
620
621        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
622        // accumulating errors for this UC.
623        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
624        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
625
626        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
627            addSearchResults(userVisit, searchType, entityInstances);
628        }
629    }
630
631    private void searchEntityTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
632        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
633                SecurityRoleGroups.EntityType.name(), SecurityRoles.Search.name())) {
634            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
635
636            if(!hasExecutionErrors()) {
637                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
638
639                if(!hasExecutionErrors()) {
640                    var userVisit = getUserVisit();
641
642                    executeEntityTypeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
643                }
644            }
645        }
646    }
647
648    private void executeEntityAliasTypeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
649            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
650            final String q) {
651        var componentVendorSearchEvaluator = new EntityAliasTypeSearchEvaluator(userVisit, null, searchType,
652                searchLogic.getDefaultSearchDefaultOperator(null),
653                searchLogic.getDefaultSearchSortOrder(null, searchKind),
654                searchLogic.getDefaultSearchSortDirection(null),
655                null);
656
657        componentVendorSearchEvaluator.setQ(null, q);
658
659        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
660        // accumulating errors for this UC.
661        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
662        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
663
664        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
665            addSearchResults(userVisit, searchType, entityInstances);
666        }
667    }
668
669    private void searchEntityAliasTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
670        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
671                SecurityRoleGroups.EntityAliasType.name(), SecurityRoles.Search.name())) {
672            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
673
674            if(!hasExecutionErrors()) {
675                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
676
677                if(!hasExecutionErrors()) {
678                    var userVisit = getUserVisit();
679
680                    executeEntityAliasTypeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
681                }
682            }
683        }
684    }
685
686    private void executeEntityAttributeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
687            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
688            final String q) {
689        var componentVendorSearchEvaluator = new EntityAttributeSearchEvaluator(userVisit, null, searchType,
690                searchLogic.getDefaultSearchDefaultOperator(null),
691                searchLogic.getDefaultSearchSortOrder(null, searchKind),
692                searchLogic.getDefaultSearchSortDirection(null),
693                null);
694
695        componentVendorSearchEvaluator.setQ(null, q);
696
697        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
698        // accumulating errors for this UC.
699        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
700        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
701
702        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
703            addSearchResults(userVisit, searchType, entityInstances);
704        }
705    }
706
707    private void searchEntityAttributes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
708        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
709                SecurityRoleGroups.EntityAttribute.name(), SecurityRoles.Search.name())) {
710            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
711
712            if(!hasExecutionErrors()) {
713                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
714
715                if(!hasExecutionErrors()) {
716                    var userVisit = getUserVisit();
717
718                    executeEntityAttributeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
719                }
720            }
721        }
722    }
723
724    private void executeEntityListItemSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
725            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
726            final String q) {
727        var componentVendorSearchEvaluator = new EntityListItemSearchEvaluator(userVisit, null, searchType,
728                searchLogic.getDefaultSearchDefaultOperator(null),
729                searchLogic.getDefaultSearchSortOrder(null, searchKind),
730                searchLogic.getDefaultSearchSortDirection(null),
731                null);
732
733        componentVendorSearchEvaluator.setQ(null, q);
734
735        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
736        // accumulating errors for this UC.
737        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
738        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
739
740        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
741            addSearchResults(userVisit, searchType, entityInstances);
742        }
743    }
744
745    private void searchEntityListItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
746        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
747                SecurityRoleGroups.EntityListItem.name(), SecurityRoles.Search.name())) {
748            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
749
750            if(!hasExecutionErrors()) {
751                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
752
753                if(!hasExecutionErrors()) {
754                    var userVisit = getUserVisit();
755
756                    executeEntityListItemSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
757                }
758            }
759        }
760    }
761
762    private void executeEntityAttributeGroupSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
763            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
764            final String q) {
765        var componentVendorSearchEvaluator = new EntityAttributeGroupSearchEvaluator(userVisit, null, searchType,
766                searchLogic.getDefaultSearchDefaultOperator(null),
767                searchLogic.getDefaultSearchSortOrder(null, searchKind),
768                searchLogic.getDefaultSearchSortDirection(null),
769                null);
770
771        componentVendorSearchEvaluator.setQ(null, q);
772
773        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
774        // accumulating errors for this UC.
775        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
776        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
777
778        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
779            addSearchResults(userVisit, searchType, entityInstances);
780        }
781    }
782
783    private void searchEntityAttributeGroups(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
784        if(securityRoleLogic.hasSecurityRoleUsingNames(this, party,
785                SecurityRoleGroups.EntityAttributeGroup.name(), SecurityRoles.Search.name())) {
786            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
787
788            if(!hasExecutionErrors()) {
789                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
790
791                if(!hasExecutionErrors()) {
792                    var userVisit = getUserVisit();
793
794                    executeEntityAttributeGroupSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
795                }
796            }
797        }
798    }
799
800    // Add results from any of the BaseSearchEvaluators to the entityInstances.
801    private void addSearchResults(final UserVisit userVisit, final SearchType searchType,
802            final Set<EntityInstanceTransfer> entityInstances) {
803        var userVisitSearch = searchLogic.getUserVisitSearch(null, userVisit, searchType);
804        var resultEntityInstances = searchControl.getUserVisitSearchEntityInstances(userVisitSearch);
805
806        for(var resultEntityInstance : resultEntityInstances) {
807            var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(resultEntityInstance);
808
809            entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
810        }
811    }
812
813    @Override
814    protected BaseResult execute() {
815        var result = SearchResultFactory.getIdentifyResult();
816        var entityInstances = new HashSet<EntityInstanceTransfer>();
817        var target = form.getTarget();
818        var party = getParty();
819
820        if(EntityNameFieldType.isValidName(target)) {
821            // Compile a list of all possible EntityInstances that the target may refer to.
822            checkSequenceTypes(party, entityInstances, target); // uses EEA
823            if(!hasExecutionErrors()) {
824                checkItems(party, entityInstances, target); // uses EEA
825            }
826            if(!hasExecutionErrors()) {
827                checkCompanies(party, entityInstances, target); // uses EEA
828            }
829            if(!hasExecutionErrors()) {
830                checkDivisions(party, entityInstances, target); // uses EEA
831            }
832            if(!hasExecutionErrors()) {
833                checkDepartments(party, entityInstances, target); // uses EEA
834            }
835            if(!hasExecutionErrors()) {
836                checkWarehouses(party, entityInstances, target); // uses EEA
837            }
838            if(!hasExecutionErrors()) {
839                checkLocations(party, entityInstances, target); // uses EEA
840            }
841            if(!hasExecutionErrors()) {
842                checkEmployees(party, entityInstances, target); // uses EEA
843            }
844            if(!hasExecutionErrors()) {
845                checkCustomers(party, entityInstances, target); // uses EEA
846            }
847            if(!hasExecutionErrors()) {
848                checkVendors(party, entityInstances, target); // uses EEA
849            }
850            if(!hasExecutionErrors()) {
851                checkVendorItems(party, entityInstances, target); // uses EEA
852            }
853            if(!hasExecutionErrors()) {
854                checkComponentVendors(party, entityInstances, target); // uses EEA
855            }
856            if(!hasExecutionErrors()) {
857                checkEntityTypes(party, entityInstances, target); // uses EEA
858            }
859            if(!hasExecutionErrors()) {
860                checkEntityAliasTypes(party, entityInstances, target); // uses EEA
861            }
862            if(!hasExecutionErrors()) {
863                checkEntityAttributes(party, entityInstances, target); // uses EEA
864            }
865            if(!hasExecutionErrors()) {
866                checkEntityListItems(party, entityInstances, target); // uses EEA
867            }
868            if(!hasExecutionErrors()) {
869                checkEntityAttributeGroups(party, entityInstances, target); // uses EEA
870            }
871        }
872
873        var nameResult = new NameCleaner().getCleansedName(target);
874        if(!hasExecutionErrors()) {
875            searchEmployees(party, entityInstances, target, nameResult); // uses EEA
876        }
877        if(!hasExecutionErrors()) {
878            searchCustomers(party, entityInstances, target, nameResult); // uses EEA
879        }
880        if(!hasExecutionErrors()) {
881            searchVendors(party, entityInstances, target, nameResult); // uses EEA
882        }
883        if(!hasExecutionErrors()) {
884            searchWarehouses(party, entityInstances, target); // uses EEA
885        }
886        if(!hasExecutionErrors()) {
887            searchItems(party, entityInstances, target); // uses EEA
888        }
889        if(!hasExecutionErrors()) {
890            searchComponentVendors(party, entityInstances, target); // uses EEA
891        }
892        if(!hasExecutionErrors()) {
893            searchEntityTypes(party, entityInstances, target); // uses EEA
894        }
895        if(!hasExecutionErrors()) {
896            searchEntityAliasTypes(party, entityInstances, target); // uses EEA
897        }
898        if(!hasExecutionErrors()) {
899            searchEntityAttributes(party, entityInstances, target); // uses EEA
900        }
901        if(!hasExecutionErrors()) {
902            searchEntityListItems(party, entityInstances, target); // uses EEA
903        }
904        if(!hasExecutionErrors()) {
905            searchEntityAttributeGroups(party, entityInstances, target); // uses EEA
906        }
907
908        result.setEntityInstances(entityInstances);
909        
910        return result;
911    }
912    
913}