turcsanyip commented on a change in pull request #4123: NIFI-7188: Adding 
filter capabilities into search & prerequisite refactors
URL: https://github.com/apache/nifi/pull/4123#discussion_r401830178
 
 

 ##########
 File path: 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerSearchService.java
 ##########
 @@ -16,688 +16,222 @@
  */
 package org.apache.nifi.web.controller;
 
-import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUser;
-import org.apache.nifi.authorization.user.NiFiUserUtils;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.validation.ValidationStatus;
-import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Funnel;
 import org.apache.nifi.connectable.Port;
 import org.apache.nifi.controller.FlowController;
 import org.apache.nifi.controller.ProcessorNode;
-import org.apache.nifi.controller.ScheduledState;
 import org.apache.nifi.controller.label.Label;
-import org.apache.nifi.controller.queue.FlowFileQueue;
 import org.apache.nifi.controller.service.ControllerServiceNode;
-import org.apache.nifi.flowfile.FlowFilePrioritizer;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.groups.RemoteProcessGroup;
-import org.apache.nifi.nar.NarCloseable;
 import org.apache.nifi.parameter.Parameter;
 import org.apache.nifi.parameter.ParameterContext;
-import org.apache.nifi.parameter.ParameterContextManager;
-import org.apache.nifi.processor.DataUnit;
-import org.apache.nifi.processor.Processor;
-import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.registry.ComponentVariableRegistry;
-import org.apache.nifi.registry.VariableDescriptor;
-import org.apache.nifi.registry.VariableRegistry;
-import org.apache.nifi.remote.PublicPort;
-import org.apache.nifi.scheduling.ExecutionNode;
-import org.apache.nifi.scheduling.SchedulingStrategy;
-import org.apache.nifi.search.SearchContext;
-import org.apache.nifi.search.SearchResult;
-import org.apache.nifi.search.Searchable;
 import org.apache.nifi.web.api.dto.search.ComponentSearchResultDTO;
-import org.apache.nifi.web.api.dto.search.SearchResultGroupDTO;
 import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
+import org.apache.nifi.web.search.ComponentMatcher;
+import org.apache.nifi.web.search.query.SearchQuery;
+import 
org.apache.nifi.web.search.resultenrichment.ComponentSearchResultEnricher;
+import 
org.apache.nifi.web.search.resultenrichment.ComponentSearchResultEnricherFactory;
 
-import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
+import java.util.Optional;
 
 /**
  * NiFi web controller's helper service that implements component search.
  */
 public class ControllerSearchService {
+    private final static String FILTER_NAME_GROUP = "group";
+    private final static String FILTER_NAME_SCOPE = "scope";
+    private final static String FILTER_SCOPE_VALUE_HERE = "here";
+
     private FlowController flowController;
     private Authorizer authorizer;
-    private VariableRegistry variableRegistry;
+    private ComponentSearchResultEnricherFactory resultEnricherFactory;
+
+    private ComponentMatcher<ProcessorNode> matcherForProcessor;
+    private ComponentMatcher<ProcessGroup> matcherForProcessGroup;
+    private ComponentMatcher<Connection> matcherForConnection;
+    private ComponentMatcher<RemoteProcessGroup> matcherForRemoteProcessGroup;
+    private ComponentMatcher<Port> matcherForPort;
+    private ComponentMatcher<Funnel> matcherForFunnel;
+    private ComponentMatcher<ParameterContext> matcherForParameterContext;
+    private ComponentMatcher<Parameter> matcherForParameter;
+    private ComponentMatcher<Label> matcherForLabel;
+    private ComponentMatcher<ControllerServiceNode> 
matcherForControllerServiceNode;
 
     /**
-     * Searches term in the controller beginning from a given process group.
+     * Searches all parameter contexts and parameters.
      *
+     * @param searchQuery Details of the search
      * @param results Search results
-     * @param search  The search term
-     * @param group   The init process group
      */
-    public void search(final SearchResultsDTO results, final String search, 
final ProcessGroup group) {
-        final NiFiUser user = NiFiUserUtils.getNiFiUser();
-
-        if (group.isAuthorized(authorizer, RequestAction.READ, user)) {
-            final ComponentSearchResultDTO groupMatch = search(search, group);
-            if (groupMatch != null) {
-                // get the parent group, not the current one
-                groupMatch.setParentGroup(buildResultGroup(group.getParent(), 
user));
-                
groupMatch.setVersionedGroup(buildVersionedGroup(group.getParent(), user));
-                results.getProcessGroupResults().add(groupMatch);
-            }
-        }
-
-        for (final ProcessorNode procNode : group.getProcessors()) {
-            if (procNode.isAuthorized(authorizer, RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, 
procNode);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getProcessorResults().add(match);
-                }
-            }
-        }
-
-        for (final Connection connection : group.getConnections()) {
-            if (connection.isAuthorized(authorizer, RequestAction.READ, user)) 
{
-                final ComponentSearchResultDTO match = search(search, 
connection);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getConnectionResults().add(match);
-                }
-            }
-        }
-
-        for (final RemoteProcessGroup remoteGroup : 
group.getRemoteProcessGroups()) {
-            if (remoteGroup.isAuthorized(authorizer, RequestAction.READ, 
user)) {
-                final ComponentSearchResultDTO match = search(search, 
remoteGroup);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getRemoteProcessGroupResults().add(match);
-                }
-            }
-        }
-
-        for (final Port port : group.getInputPorts()) {
-            if (port.isAuthorized(authorizer, RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, port);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getInputPortResults().add(match);
-                }
-            }
+    public void search(final SearchQuery searchQuery, final SearchResultsDTO 
results) {
+        if (searchQuery.hasFilter(FILTER_NAME_SCOPE) && 
FILTER_SCOPE_VALUE_HERE.equals(searchQuery.getFilter(FILTER_NAME_SCOPE))) {
+            searchInProcessGroup(results, searchQuery, 
searchQuery.getActiveGroup());
+        } else {
+            searchInProcessGroup(results, searchQuery, 
searchQuery.getRootGroup());
         }
+    }
 
-        for (final Port port : group.getOutputPorts()) {
-            if (port.isAuthorized(authorizer, RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, port);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getOutputPortResults().add(match);
-                }
-            }
-        }
+    private void searchInProcessGroup(final SearchResultsDTO results, final 
SearchQuery searchQuery, final ProcessGroup scope) {
+        final NiFiUser user = searchQuery.getUser();
+        final ComponentSearchResultEnricher resultEnricher = 
resultEnricherFactory.getComponentResultEnricher(scope, user);
+        final ComponentSearchResultEnricher groupResultEnricher = 
resultEnricherFactory.getProcessGroupResultEnricher(scope, user);
 
-        for (final Funnel funnel : group.getFunnels()) {
-            if (funnel.isAuthorized(authorizer, RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, funnel);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getFunnelResults().add(match);
-                }
+        if (appliesToGroupFilter(searchQuery, scope)) {
+            if (scope.getParent() != null) {
+                searchComponentType(Collections.singletonList(scope), user, 
searchQuery, matcherForProcessGroup, groupResultEnricher, 
results.getProcessGroupResults());
             }
-        }
 
-        for (final Label label : group.getLabels()) {
-            if (label.isAuthorized(authorizer, RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, label);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getLabelResults().add(match);
-                }
-            }
+            searchComponentType(scope.getProcessors(), user, searchQuery, 
matcherForProcessor, resultEnricher, results.getProcessorResults());
+            searchComponentType(scope.getConnections(), user, searchQuery, 
matcherForConnection, resultEnricher, results.getConnectionResults());
+            searchComponentType(scope.getRemoteProcessGroups(), user, 
searchQuery, matcherForRemoteProcessGroup, resultEnricher, 
results.getRemoteProcessGroupResults());
+            searchComponentType(scope.getInputPorts(), user, searchQuery, 
matcherForPort, resultEnricher, results.getInputPortResults());
+            searchComponentType(scope.getOutputPorts(), user, searchQuery, 
matcherForPort, resultEnricher, results.getOutputPortResults());
+            searchComponentType(scope.getFunnels(), user, searchQuery, 
matcherForFunnel, resultEnricher, results.getFunnelResults());
+            searchComponentType(scope.getLabels(), user, searchQuery, 
matcherForLabel, resultEnricher, results.getLabelResults());
+            searchComponentType(scope.getControllerServices(false), user, 
searchQuery, matcherForControllerServiceNode, resultEnricher, 
results.getControllerServiceNodeResults());
         }
 
-        for (final ControllerServiceNode controllerServiceNode : 
group.getControllerServices(false)) {
-            if (controllerServiceNode.isAuthorized(authorizer, 
RequestAction.READ, user)) {
-                final ComponentSearchResultDTO match = search(search, 
controllerServiceNode);
-                if (match != null) {
-                    match.setGroupId(group.getIdentifier());
-                    match.setParentGroup(buildResultGroup(group, user));
-                    match.setVersionedGroup(buildVersionedGroup(group, user));
-                    results.getControllerServiceNodeResults().add(match);
-                }
-            }
-        }
-
-        for (final ProcessGroup processGroup : group.getProcessGroups()) {
-            search(results, search, processGroup);
-        }
+        scope.getProcessGroups().forEach(processGroup -> 
searchInProcessGroup(results, searchQuery, processGroup));
     }
 
-    /**
-     * Searches controller service for the given search term
-     *
-     * @param search                the search term
-     * @param controllerServiceNode a group controller service node
-     */
-    private ComponentSearchResultDTO search(final String search, final 
ControllerServiceNode controllerServiceNode) {
-        final List<String> matches = new ArrayList<>();
-        addIfAppropriate(search, controllerServiceNode.getIdentifier(), "Id", 
matches);
-        addIfAppropriate(search, 
controllerServiceNode.getVersionedComponentId().orElse(null), "Version Control 
ID", matches);
-        addIfAppropriate(search, controllerServiceNode.getName(), "Name", 
matches);
-        addIfAppropriate(search, controllerServiceNode.getComments(), 
"Comments", matches);
-
-        // search property values
-        controllerServiceNode.getRawPropertyValues().forEach((property, 
propertyValue) -> {
-            addIfAppropriate(search, property.getName(), "Property Name", 
matches);
-            addIfAppropriate(search, property.getDescription(), "Property 
Description", matches);
-
-            // never include sensitive properties in search results
-            if (property.isSensitive()) {
-                return;
-            }
-
-            if (propertyValue != null) {
-                addIfAppropriate(search, propertyValue, "Property Value", 
matches);
-            } else {
-                addIfAppropriate(search, property.getDefaultValue(), "Property 
Value", matches);
-            }
-        });
-
-        if (matches.isEmpty()) {
-            return null;
-        }
-
-        final ComponentSearchResultDTO dto = new ComponentSearchResultDTO();
-        dto.setId(controllerServiceNode.getIdentifier());
-        dto.setName(controllerServiceNode.getName());
-        dto.setMatches(matches);
-        return dto;
+    private boolean appliesToGroupFilter(final SearchQuery searchQuery, final 
ProcessGroup scope) {
+        return !searchQuery.hasFilter(FILTER_NAME_GROUP) || 
eligibleForGroupFilter(scope, searchQuery.getFilter(FILTER_NAME_GROUP));
     }
 
     /**
-     * Searches all parameter contexts and parameters
+     * Check is the group is eligible for the filter value. It might be 
eligible based on name or id.
      *
-     * @param results Search results
-     * @param search  The search term
+     * @param scope The subject process group.
+     * @param filterValue The value to match against.
+     *
+     * @return True in case the scope process group or any parent is matching. 
A group is matching when it's name or it's id contains the filter value.
      */
-    public void searchParameters(final SearchResultsDTO results, final String 
search) {
-        final NiFiUser user = NiFiUserUtils.getNiFiUser();
-        ParameterContextManager parameterContextManager = 
flowController.getFlowManager().getParameterContextManager();
-
-        final Set<ParameterContext> parameterContexts = 
parameterContextManager.getParameterContexts();
-        for (final ParameterContext parameterContext : parameterContexts) {
-            if (parameterContext.isAuthorized(authorizer, RequestAction.READ, 
user)) {
-                ComponentSearchResultDTO parameterContextMatch = 
search(search, parameterContext);
-                if (parameterContextMatch != null) {
-                    
results.getParameterContextResults().add(parameterContextMatch);
-                }
-
-                // search each parameter within the context as well
-                for (Parameter parameter : 
parameterContext.getParameters().values()) {
-                    ComponentSearchResultDTO parameterMatch = search(search, 
parameter);
-                    if (parameterMatch != null) {
-                        final SearchResultGroupDTO paramContextGroup = new 
SearchResultGroupDTO();
-                        
paramContextGroup.setId(parameterContext.getIdentifier());
-                        paramContextGroup.setName(parameterContext.getName());
-                        parameterMatch.setParentGroup(paramContextGroup);
-
-                        results.getParameterResults().add(parameterMatch);
-                    }
-                }
-            }
-        }
-    }
-
-    private ComponentSearchResultDTO search(final String searchStr, final Port 
port) {
-        final List<String> matches = new ArrayList<>();
+    private boolean eligibleForGroupFilter(final ProcessGroup scope, final 
String filterValue) {
+        final List<ProcessGroup> lineage = getLineage(scope);
 
-        addIfAppropriate(searchStr, port.getIdentifier(), "Id", matches);
-        addIfAppropriate(searchStr, 
port.getVersionedComponentId().orElse(null), "Version Control ID", matches);
-        addIfAppropriate(searchStr, port.getName(), "Name", matches);
-        addIfAppropriate(searchStr, port.getComments(), "Comments", matches);
-
-        // consider scheduled state
-        if (ScheduledState.DISABLED.equals(port.getScheduledState())) {
-            if (StringUtils.containsIgnoreCase("disabled", searchStr)) {
-                matches.add("Run status: Disabled");
-            }
-        } else {
-            if (StringUtils.containsIgnoreCase("invalid", searchStr) && 
!port.isValid()) {
-                matches.add("Run status: Invalid");
-            } else if (ScheduledState.RUNNING.equals(port.getScheduledState()) 
&& StringUtils.containsIgnoreCase("running", searchStr)) {
-                matches.add("Run status: Running");
-            } else if (ScheduledState.STOPPED.equals(port.getScheduledState()) 
&& StringUtils.containsIgnoreCase("stopped", searchStr)) {
-                matches.add("Run status: Stopped");
-            }
-        }
-
-        if (port instanceof PublicPort) {
-            final PublicPort publicPort = (PublicPort) port;
-
-            // user access controls
-            for (final String userAccessControl : 
publicPort.getUserAccessControl()) {
-                addIfAppropriate(searchStr, userAccessControl, "User access 
control", matches);
+        for (final ProcessGroup group : lineage) {
+            if (StringUtils.containsIgnoreCase(group.getName(), filterValue) 
|| StringUtils.containsIgnoreCase(group.getIdentifier(), filterValue)) {
+                return true;
             }
-
-            // group access controls
-            for (final String groupAccessControl : 
publicPort.getGroupAccessControl()) {
-                addIfAppropriate(searchStr, groupAccessControl, "Group access 
control", matches);
-            }
-        }
-
-        if (matches.isEmpty()) {
-            return null;
         }
 
-        final ComponentSearchResultDTO dto = new ComponentSearchResultDTO();
-        dto.setId(port.getIdentifier());
-        dto.setName(port.getName());
-        dto.setMatches(matches);
-        return dto;
+        return false;
     }
 
-    private ComponentSearchResultDTO search(final String searchStr, final 
ProcessorNode procNode) {
-        final List<String> matches = new ArrayList<>();
-        final Processor processor = procNode.getProcessor();
-
-        addIfAppropriate(searchStr, procNode.getIdentifier(), "Id", matches);
-        addIfAppropriate(searchStr, 
procNode.getVersionedComponentId().orElse(null), "Version Control ID", matches);
-        addIfAppropriate(searchStr, procNode.getName(), "Name", matches);
-        addIfAppropriate(searchStr, procNode.getComments(), "Comments", 
matches);
-
-        // consider scheduling strategy
-        if 
(SchedulingStrategy.EVENT_DRIVEN.equals(procNode.getSchedulingStrategy()) && 
StringUtils.containsIgnoreCase("event", searchStr)) {
-            matches.add("Scheduling strategy: Event driven");
-        } else if 
(SchedulingStrategy.TIMER_DRIVEN.equals(procNode.getSchedulingStrategy()) && 
StringUtils.containsIgnoreCase("timer", searchStr)) {
-            matches.add("Scheduling strategy: Timer driven");
-        } else if 
(SchedulingStrategy.PRIMARY_NODE_ONLY.equals(procNode.getSchedulingStrategy()) 
&& StringUtils.containsIgnoreCase("primary", searchStr)) {
-            // PRIMARY_NODE_ONLY has been deprecated as a SchedulingStrategy 
and replaced by PRIMARY as an ExecutionNode.
-            matches.add("Scheduling strategy: On primary node");
-        }
-
-        // consider execution node
-        if (ExecutionNode.PRIMARY.equals(procNode.getExecutionNode()) && 
StringUtils.containsIgnoreCase("primary", searchStr)) {
-            matches.add("Execution node: primary");
-        }
-
-        // consider scheduled state
-        if (ScheduledState.DISABLED.equals(procNode.getScheduledState())) {
-            if (StringUtils.containsIgnoreCase("disabled", searchStr)) {
-                matches.add("Run status: Disabled");
-            }
-        } else {
-            if (StringUtils.containsIgnoreCase("invalid", searchStr) && 
procNode.getValidationStatus() == ValidationStatus.INVALID) {
-                matches.add("Run status: Invalid");
-            } else if (StringUtils.containsIgnoreCase("validating", searchStr) 
&& procNode.getValidationStatus() == ValidationStatus.VALIDATING) {
-                matches.add("Run status: Validating");
-            } else if 
(ScheduledState.RUNNING.equals(procNode.getScheduledState()) && 
StringUtils.containsIgnoreCase("running", searchStr)) {
-                matches.add("Run status: Running");
-            } else if 
(ScheduledState.STOPPED.equals(procNode.getScheduledState()) && 
StringUtils.containsIgnoreCase("stopped", searchStr)) {
-                matches.add("Run status: Stopped");
-            }
-        }
+    private List<ProcessGroup> getLineage(final ProcessGroup group) {
+        final LinkedList<ProcessGroup> result = new LinkedList<>();
 
 Review comment:
   Just an idea but it would be more straightforward for me in this way:
   
   ```
           final LinkedList<ProcessGroup> result = new LinkedList<>();
           
           ProcessGroup current = group;
           while (current != null) {
               result.addLast(current);
               current = current.getParent();
           }
   
           return result;
   ```
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to