Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion db/sql/test/populate_entity_info.sql
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ INSERT INTO `entity_info` VALUES
(186,1,1,1,'2025-04-02 08:43:31',1,'2025-04-02 08:43:31',1,NULL,NULL),
(187,1,1,1,'2026-10-27 10:43:43',1,'2026-10-27 10:44:07',1,NULL,NULL),
(188,1,1,1,'2026-10-27 10:44:00',1,'2026-10-27 10:44:00',1,NULL,NULL),
(189,1,1,1,'2026-10-27 10:44:00',1,'2026-10-27 10:44:19',1,NULL,NULL);
(189,1,1,1,'2026-10-27 10:44:00',1,'2026-10-27 10:44:19',1,NULL,NULL),
(190,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(191,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(192,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(193,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(194,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(195,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(196,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(197,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL),
(198,1,1,1,'2026-10-28 09:00:00',1,'2026-10-28 09:00:00',1,NULL,NULL);
/*!40000 ALTER TABLE `entity_info` ENABLE KEYS */;
UNLOCK TABLES;
8 changes: 7 additions & 1 deletion db/sql/test/populate_item.sql
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ INSERT INTO `item` VALUES
(126,6,'Item with Ports 3',NULL,NULL,NULL,NULL),
(127,2,'Item With Connectors 3',NULL,'','',NULL),
(128,6,'Another Top Level ',NULL,NULL,NULL,NULL),
(129,6,'Inventory Assignment Test Destination',NULL,NULL,NULL,NULL);
(129,6,'Inventory Assignment Test Destination',NULL,NULL,NULL,NULL),
(130,3,'Machine Assignment Test Inventory',1,NULL,NULL,NULL),
(131,6,'Machine Assignment Test Source',NULL,NULL,NULL,NULL),
(132,6,'Machine Assignment Test Component 1',NULL,NULL,NULL,NULL),
(133,6,'Machine Assignment Test Component 2',NULL,NULL,NULL,NULL),
(134,6,'Machine Assignment Replacement Root',NULL,NULL,NULL,NULL),
(135,6,'Machine Assignment Replacement Destination',NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `item` ENABLE KEYS */;
UNLOCK TABLES;
11 changes: 10 additions & 1 deletion db/sql/test/populate_item_element.sql
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ INSERT INTO `item_element` VALUES
(186,NULL,127,NULL,NULL,NULL,NULL,0,1,'',NULL,186),
(187,NULL,128,NULL,NULL,NULL,NULL,0,1,'',NULL,187),
(188,'E1',128,129,NULL,NULL,NULL,0,1,NULL,0.00,188),
(189,NULL,129,NULL,40,NULL,NULL,0,1,'',NULL,189);
(189,NULL,129,NULL,40,NULL,NULL,0,1,'',NULL,189),
(190,NULL,130,NULL,NULL,NULL,NULL,0,1,'',NULL,190),
(191,NULL,131,NULL,NULL,NULL,NULL,0,1,'',NULL,191),
(192,NULL,132,NULL,1,NULL,NULL,0,1,'',NULL,192),
(193,'E1',131,132,NULL,NULL,NULL,0,1,NULL,0.00,193),
(194,NULL,133,NULL,1,NULL,NULL,0,1,'',NULL,194),
(195,'E2',131,133,NULL,NULL,NULL,0,1,NULL,1.00,195),
(196,NULL,134,NULL,NULL,NULL,NULL,0,1,'',NULL,196),
(197,NULL,135,NULL,40,NULL,NULL,0,1,'',NULL,197),
(198,'E1',134,135,NULL,NULL,NULL,0,1,NULL,0.00,198);
/*!40000 ALTER TABLE `item_element` ENABLE KEYS */;
UNLOCK TABLES;
8 changes: 7 additions & 1 deletion db/sql/test/populate_item_item_project.sql
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ INSERT INTO `item_item_project` VALUES
(126,3),
(127,3),
(128,3),
(129,3);
(129,3),
(130,3),
(131,3),
(132,3),
(133,3),
(134,3),
(135,3);
/*!40000 ALTER TABLE `item_item_project` ENABLE KEYS */;
UNLOCK TABLES;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ public static boolean isEmailAddressValid(String emailAddress){
return emailPattern.matcher(emailAddress).matches();
}

public static Pattern buildWildcardSearchPattern(String searchString, boolean caseInsensitive) {
StringBuilder regex = new StringBuilder();
for (int i = 0; i < searchString.length(); i++) {
char character = searchString.charAt(i);
if (character == '*') {
regex.append(".*");
} else if (character == '?') {
regex.append('.');
} else {
regex.append(Pattern.quote(String.valueOf(character)));
}
}
int flags = caseInsensitive ? Pattern.CASE_INSENSITIVE : 0;
return Pattern.compile(regex.toString(), flags);
}

/**
* Verify that two char sequences are the same.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import gov.anl.aps.cdb.common.constants.CdbRole;
import gov.anl.aps.cdb.common.exceptions.CdbException;
import gov.anl.aps.cdb.common.utilities.StringUtility;
import gov.anl.aps.cdb.portal.constants.ItemDomainName;
import gov.anl.aps.cdb.portal.import_export.import_.helpers.ImportHelperInventory;
import gov.anl.aps.cdb.portal.controllers.extensions.ItemCreateWizardController;
Expand All @@ -21,8 +22,10 @@
import gov.anl.aps.cdb.portal.model.ItemDomainInventoryLazyDataModel;
import gov.anl.aps.cdb.portal.model.ItemDomainMachineDesignTreeNode;
import gov.anl.aps.cdb.portal.model.db.beans.ItemDomainInventoryFacade;
import gov.anl.aps.cdb.portal.model.db.beans.ItemDomainMachineDesignFacade;
import gov.anl.aps.cdb.portal.model.db.entities.EntityType;
import gov.anl.aps.cdb.portal.model.db.entities.Item;
import gov.anl.aps.cdb.portal.model.db.entities.ItemDomainCatalog;
import gov.anl.aps.cdb.portal.model.db.entities.ItemDomainInventory;
import gov.anl.aps.cdb.portal.model.db.entities.ItemDomainMachineDesign;
import gov.anl.aps.cdb.portal.model.db.entities.ItemElement;
Expand All @@ -34,7 +37,10 @@
import gov.anl.aps.cdb.portal.view.objects.DomainImportExportInfo;
import gov.anl.aps.cdb.portal.view.objects.ImportExportFormatInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
Expand Down Expand Up @@ -64,6 +70,9 @@ public class ItemDomainInventoryController extends ItemDomainInventoryBaseContro
@EJB
private ItemDomainInventoryFacade itemDomainInventoryFacade;

@EJB
private ItemDomainMachineDesignFacade itemDomainMachineDesignFacade;

private final InventoryMachineAssignmentSelection machineAssignmentSelection
= new InventoryMachineAssignmentSelection();

Expand All @@ -88,6 +97,38 @@ public void setSelectedMachineAssignmentNode(ItemDomainMachineDesignTreeNode nod
machineAssignmentSelection.setReplacementConfirmation(false);
}

public boolean isMachineAssignmentMatchingCatalogOnly() {
return machineAssignmentSelection.isMatchingCatalogOnly();
}

public void setMachineAssignmentMatchingCatalogOnly(boolean matchingCatalogOnly) {
machineAssignmentSelection.setMatchingCatalogOnly(matchingCatalogOnly);
}

public String getMachineAssignmentNameFilter() {
return machineAssignmentSelection.getMachineNameFilter();
}

public void setMachineAssignmentNameFilter(String nameFilter) {
machineAssignmentSelection.setMachineNameFilter(nameFilter);
}

public void updateMachineAssignmentCatalogFilter() {
ItemDomainMachineDesign selectedMachine = machineAssignmentSelection.getSelectedMachine();
ItemDomainMachineDesignTreeNode tree
= ItemDomainMachineDesignController.getInstance().loadMachineDesignRootTreeNode();
if (machineAssignmentSelection.isMatchingCatalogOnly()) {
tree.buildResultTree(getMachinesMatchingCurrentInventoryCatalog());
}
machineAssignmentSelection.setAssignmentTree(tree);
if (selectedMachine != null) {
ItemDomainMachineDesignTreeNode selectedNode
= (ItemDomainMachineDesignTreeNode) ItemDomainMachineDesignController
.expandToSpecificMachineDesignItem(tree, selectedMachine);
machineAssignmentSelection.setSelectedNode(selectedNode);
}
}

public boolean isMachineAssignmentInstalled() {
return machineAssignmentSelection.isInstalled();
}
Expand Down Expand Up @@ -288,6 +329,59 @@ protected Item getCatalogItem(Item item) {
return item instanceof ItemDomainInventory ? item.getDerivedFromItem() : item;
}

protected List<ItemDomainMachineDesign> getMachinesMatchingCurrentInventoryCatalog() {
Item catalog = getCurrentInventoryCatalog();
if (!(catalog instanceof ItemDomainCatalog)) {
return new ArrayList<>();
}
return filterMachinesByCatalogAndHierarchyName(
itemDomainMachineDesignFacade.findByAssignedCatalog((ItemDomainCatalog) catalog),
catalog, machineAssignmentSelection.getMachineNameFilter());
}

static List<ItemDomainMachineDesign> filterMachinesByCatalogAndHierarchyName(
List<ItemDomainMachineDesign> machines, Item catalog, String nameFilter) {
Pattern namePattern = createWildcardPattern(nameFilter);
List<ItemDomainMachineDesign> matches = new ArrayList<>();
for (ItemDomainMachineDesign machine : machines) {
if (catalog.equals(machine.getCatalogItem())
&& hierarchyNameMatches(machine, namePattern)) {
matches.add(machine);
}
}
return matches;
}

private static boolean hierarchyNameMatches(
ItemDomainMachineDesign machine, Pattern namePattern) {
if (namePattern == null) {
return true;
}
Set<Integer> visitedIds = new HashSet<>();
Set<ItemDomainMachineDesign> visitedItems = new HashSet<>();
ItemDomainMachineDesign current = machine;
while (current != null) {
Integer id = current.getId();
if ((id != null && !visitedIds.add(id))
|| (id == null && !visitedItems.add(current))) {
break;
}
String name = current.getName();
if (name != null && namePattern.matcher(name).find()) {
return true;
}
current = current.getParentMachineDesign();
}
return false;
}

private static Pattern createWildcardPattern(String nameFilter) {
if (nameFilter == null || nameFilter.isBlank()) {
return null;
}
return StringUtility.buildWildcardSearchPattern(nameFilter, true);
}

protected boolean requiresCatalogReplacementConfirmation(ItemDomainMachineDesign machine) {
Item assignment = machine.getAssignedItem();
if (assignment == null || assignment.equals(getCurrent())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,19 +414,7 @@ public LinkedList<SearchResult> performEntitySearch(String searchString, boolean
* @return compiled search pattern
*/
protected Pattern buildSearchPattern(String searchString, boolean caseInsensitive) {
String patternString;
if (searchString.contains("?") || searchString.contains("*")) {
patternString = searchString.replace("*", ".*");
patternString = patternString.replace("?", ".");
} else {
patternString = Pattern.quote(searchString);
}

if (caseInsensitive) {
return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
} else {
return Pattern.compile(patternString);
}
return StringUtility.buildWildcardSearchPattern(searchString, caseInsensitive);
}

public PropertyValue preparePropertyTypeValueAdd(EntityType cdbDomainEntity, PropertyType propertyType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public abstract class ItemDomainMachineDesignBaseTreeNode<MachineNodeConfigurati
private List<ItemDomainMachineDesign> rawFilterResults;
private List<ItemDomainMachineDesign> filterResults;
private Boolean filterAllNodes;
private boolean includeAllTopLevelResults;

protected ItemDomainMachineDesignBaseTreeNode(ItemElement element, MachineNodeConfiguration config, ItemDomainMachineDesignBaseTreeNode parent, boolean setTypeForLevel) {
super(element, config, parent);
Expand Down Expand Up @@ -299,34 +300,49 @@ public void filterChangeEvent(String onComplete) {

public void finishFiltering() {
if (rawFilterResults != null) {
getChildren().clear();

AtomicInteger relevantResults = new AtomicInteger(0);
filterResults = new ArrayList<>();
// Passed as array to force pass by reference.
Integer[] displayedNodes = new Integer[1];
displayedNodes[0] = 0;
for (ItemDomainMachineDesign item : rawFilterResults) {
Set<ItemDomainMachineDesign> additionalParents = new HashSet<>();
List<ItemDomainMachineDesign> processParents = new ArrayList<>();

ItemDomainMachineDesignBaseTreeNode createTreeFromFilter = createTreeFromFilter(item, true, displayedNodes, additionalParents, null);
processAdditionalFilterParentResult(item, additionalParents, processParents, relevantResults, displayedNodes);

if (createTreeFromFilter != null) {
relevantResults.incrementAndGet();
filterResults.add(item);
}
}
buildResultTree(rawFilterResults, true);
}
}

Integer maxSearchNodes = config.getMaxSearchNodes();
if (displayedNodes[0] > maxSearchNodes) {
clearFilterResults();
SessionUtility.addErrorMessage("Too many results rows (" + displayedNodes[0] + ")", "Too many results to display. Please provide a more specific search criteria.", true);
} else {
SessionUtility.addInfoMessage("Done", "Showing " + relevantResults + " relevant results.", true);
public void buildResultTree(List<ItemDomainMachineDesign> results) {
includeAllTopLevelResults = true;
try {
buildResultTree(results, false);
} finally {
includeAllTopLevelResults = false;
}
}

private void buildResultTree(List<ItemDomainMachineDesign> results, boolean displayMessages) {
getChildren().clear();

AtomicInteger relevantResults = new AtomicInteger(0);
filterResults = new ArrayList<>();
// Passed as array to force pass by reference.
Integer[] displayedNodes = new Integer[]{0};
for (ItemDomainMachineDesign item : results) {
Set<ItemDomainMachineDesign> additionalParents = new HashSet<>();
List<ItemDomainMachineDesign> processParents = new ArrayList<>();

ItemDomainMachineDesignBaseTreeNode resultNode
= createTreeFromFilter(item, true, displayedNodes, additionalParents, null);
processAdditionalFilterParentResult(item, additionalParents, processParents,
relevantResults, displayedNodes);

if (resultNode != null) {
relevantResults.incrementAndGet();
filterResults.add(item);
}
}

Integer maxSearchNodes = config.getMaxSearchNodes();
if (displayMessages && displayedNodes[0] > maxSearchNodes) {
clearFilterResults();
SessionUtility.addErrorMessage("Too many results rows (" + displayedNodes[0] + ")",
"Too many results to display. Please provide a more specific search criteria.", true);
} else if (displayMessages) {
SessionUtility.addInfoMessage("Done", "Showing " + relevantResults + " relevant results.", true);
}
}

private void processAdditionalFilterParentResult(ItemDomainMachineDesign item, Set<ItemDomainMachineDesign> additionalParents, List<ItemDomainMachineDesign> processParents, AtomicInteger relevantResults, Integer[] displayedNodes) {
Expand Down Expand Up @@ -436,6 +452,9 @@ private ItemDomainMachineDesignBaseTreeNode createTreeFromFilter(ItemDomainMachi
}

private boolean isFilterTopLevelItem(ItemDomainMachineDesign item) {
if (includeAllTopLevelResults) {
return topLevelItems.contains(item);
}
for (ItemDomainMachineDesign topItem : topLevelItems) {
if (topItem.equals(item)) {
return topItem.isFilterMachineNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import gov.anl.aps.cdb.common.exceptions.CdbException;
import gov.anl.aps.cdb.portal.constants.EntityTypeName;
import gov.anl.aps.cdb.portal.constants.ItemDomainName;
import gov.anl.aps.cdb.portal.model.db.entities.ItemDomainCatalog;
import gov.anl.aps.cdb.portal.model.db.entities.ItemDomainMachineDesign;
import gov.anl.aps.cdb.portal.model.db.entities.ItemElement;
import gov.anl.aps.cdb.portal.model.db.entities.ListTbl;
Expand Down Expand Up @@ -83,6 +84,23 @@ public List<ItemDomainMachineDesign> searchIOCItems(String searchString) {
.getResultList();
}

public List<ItemDomainMachineDesign> findByAssignedCatalog(ItemDomainCatalog catalog) {
if (catalog == null || catalog.getId() == null) {
return java.util.Collections.emptyList();
}
return em.createQuery(
"SELECT DISTINCT machine FROM ItemDomainMachineDesign machine "
+ "JOIN machine.fullItemElementList element "
+ "JOIN element.containedItem2 assignment "
+ "WHERE element.name IS NULL "
+ "AND element.derivedFromItemElement IS NULL "
+ "AND (assignment.id = :catalogId "
+ "OR assignment.derivedFromItem.id = :catalogId)",
ItemDomainMachineDesign.class)
.setParameter("catalogId", catalog.getId())
.getResultList();
}

public List<ItemDomainMachineDesign> getMachineDesignTemplates() {
return findByDomainAndEntityType(
ItemDomainName.machineDesign.getValue(),
Expand Down
Loading
Loading