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