package com.thinkbiganalytics.nifi.rest.client; /*- * #%L * thinkbig-nifi-rest-client-api * %% * Copyright (C) 2017 ThinkBig Analytics * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import com.thinkbiganalytics.nifi.feedmgr.TemplateCreationHelper; import com.thinkbiganalytics.nifi.rest.model.flow.NifiFlowProcessGroup; import com.thinkbiganalytics.nifi.rest.model.visitor.NifiFlowBuilder; import com.thinkbiganalytics.nifi.rest.model.visitor.NifiVisitableProcessGroup; import com.thinkbiganalytics.nifi.rest.model.visitor.NifiVisitableProcessor; import com.thinkbiganalytics.nifi.rest.support.NifiConstants; import com.thinkbiganalytics.nifi.rest.support.NifiProcessUtil; import com.thinkbiganalytics.nifi.rest.visitor.NifiConnectionOrderVisitor; import com.thinkbiganalytics.nifi.rest.visitor.NifiConnectionOrderVisitorCache; import com.thinkbiganalytics.support.FeedNameUtil; import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.ProcessorDTO; import org.apache.nifi.web.api.dto.TemplateDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; /** */ public class DefaultNiFiFlowVisitorClient implements NiFiFlowVisitorClient { private static final Logger log = LoggerFactory.getLogger(DefaultNiFiFlowVisitorClient.class); private NiFiRestClient restClient; public DefaultNiFiFlowVisitorClient(NiFiRestClient restClient) { this.restClient = restClient; } public NifiVisitableProcessGroup getFlowOrder(String processGroupId, NifiConnectionOrderVisitorCache cache) throws NifiComponentNotFoundException { ProcessGroupDTO processGroupEntity = restClient.processGroups().findById(processGroupId, true, true).orElse(null); return getFlowOrder(processGroupEntity, cache); } public NifiVisitableProcessGroup getFlowOrder(ProcessGroupDTO processGroupEntity, NifiConnectionOrderVisitorCache cache) throws NifiComponentNotFoundException { return getFlowOrder(processGroupEntity, cache, true); } /** * @param quiet dont throw any NotFound exceptions from the REST API */ public NifiVisitableProcessGroup getFlowOrder(ProcessGroupDTO processGroupEntity, NifiConnectionOrderVisitorCache cache, boolean logRestAccessErrors) throws NifiComponentNotFoundException { if (cache == null) { cache = new NifiConnectionOrderVisitorCache(); } final NifiConnectionOrderVisitorCache finalCache = cache; Optional<ProcessGroupDTO> cachedProcessGroup = cache.getProcessGroup(processGroupEntity.getId()); if (!cachedProcessGroup.isPresent() && processGroupEntity.getContents() != null) { NifiProcessUtil.getProcessGroups(processGroupEntity).stream().forEach(processGroupDTO -> finalCache.add(processGroupDTO)); } NifiVisitableProcessGroup group = null; if (processGroupEntity != null) { group = new NifiVisitableProcessGroup(processGroupEntity); NifiConnectionOrderVisitor orderVisitor = new NifiConnectionOrderVisitor(restClient, group, finalCache); try { Optional<ProcessGroupDTO> parent = cache.getProcessGroup(processGroupEntity.getParentGroupId()); if (!parent.isPresent()) { parent = restClient.processGroups().findById(processGroupEntity.getParentGroupId(), false, false, logRestAccessErrors); } if (parent.isPresent()) { group.setParentProcessGroup(parent.get()); } } catch (NifiComponentNotFoundException e) { //cant find the parent } group.accept(orderVisitor); finalCache.add(orderVisitor.toCachedItem()); } return group; } public NifiFlowProcessGroup getFeedFlow(String processGroupId) { return getFeedFlow(processGroupId, null); } public NifiFlowProcessGroup getFeedFlow(String processGroupId, NifiConnectionOrderVisitorCache cache) { NifiVisitableProcessGroup visitableGroup = getFlowOrder(processGroupId, cache); NifiFlowProcessGroup flow = new NifiFlowBuilder().build(visitableGroup); String categoryName = flow.getParentGroupName(); String feedName = flow.getName(); feedName = FeedNameUtil.fullName(categoryName, feedName); //if it is a versioned feed then strip the version to get the correct feed name feedName = TemplateCreationHelper.parseVersionedProcessGroupName(feedName); flow.setFeedName(feedName); return flow; } public Set<ProcessorDTO> getProcessorsForFlow(String processGroupId) throws NifiComponentNotFoundException { NifiVisitableProcessGroup group = getFlowOrder(processGroupId, null); Set<ProcessorDTO> processors = new HashSet<>(); for (NifiVisitableProcessor p : group.getStartingProcessors()) { processors.addAll(p.getProcessors()); } return processors; } public NifiFlowProcessGroup getFeedFlowForCategoryAndFeed(String categoryAndFeedName) { NifiFlowProcessGroup flow = null; String category = FeedNameUtil.category(categoryAndFeedName); String feed = FeedNameUtil.feed(categoryAndFeedName); //1 find the ProcessGroup under "root" matching the name category ProcessGroupDTO processGroupEntity = restClient.processGroups().findRoot(); ProcessGroupDTO root = processGroupEntity; ProcessGroupDTO categoryGroup = root.getContents().getProcessGroups().stream().filter(group -> category.equalsIgnoreCase(group.getName())).findAny().orElse(null); if (categoryGroup != null) { ProcessGroupDTO feedGroup = categoryGroup.getContents().getProcessGroups().stream().filter(group -> feed.equalsIgnoreCase(group.getName())).findAny().orElse(null); if (feedGroup != null) { flow = getFeedFlow(feedGroup.getId()); } } return flow; } public List<NifiFlowProcessGroup> getFeedFlows(Collection<String> feedNames) { log.info("get Graph of Nifi Flows looking for {} ", feedNames == null ? "ALL Feeds " : feedNames); long start = System.currentTimeMillis(); NifiConnectionOrderVisitorCache cache = new NifiConnectionOrderVisitorCache(); List<NifiFlowProcessGroup> feedFlows = new ArrayList<>(); ProcessGroupDTO processGroupEntity = restClient.processGroups().findRoot(); ProcessGroupDTO root = processGroupEntity; //first level is the category root.getContents().getProcessGroups().stream().sorted(new Comparator<ProcessGroupDTO>() { @Override public int compare(ProcessGroupDTO o1, ProcessGroupDTO o2) { if (TemplateCreationHelper.REUSABLE_TEMPLATES_PROCESS_GROUP_NAME.equalsIgnoreCase(o1.getName())) { return -1; } if (TemplateCreationHelper.REUSABLE_TEMPLATES_PROCESS_GROUP_NAME.equalsIgnoreCase(o2.getName())) { return -1; } return o1.getName().compareTo(o2.getName()); } }).forEach(category -> { for (ProcessGroupDTO feedProcessGroup : category.getContents().getProcessGroups()) { //second level is the feed String feedName = FeedNameUtil.fullName(category.getName(), feedProcessGroup.getName()); //if it is a versioned feed then strip the version to get the correct feed name feedName = TemplateCreationHelper.parseVersionedProcessGroupName(feedName); //if feednames are sent in, only add those that match or those in the reusable group if ((feedNames == null || feedNames.isEmpty()) || (feedNames != null && (feedNames.contains(feedName) || TemplateCreationHelper.REUSABLE_TEMPLATES_PROCESS_GROUP_NAME .equalsIgnoreCase(category.getName())))) { NifiFlowProcessGroup feedFlow = getFeedFlow(feedProcessGroup.getId(), cache); feedFlow.setFeedName(feedName); feedFlows.add(feedFlow); } } }); long end = System.currentTimeMillis(); log.info("finished Graph of Nifi Flows. Returning {} flows, {} ", feedFlows.size(), (end - start) + " ms"); return feedFlows; } //walk entire graph public List<NifiFlowProcessGroup> getFeedFlows() { return getFeedFlows(null); } public NifiFlowProcessGroup getTemplateFeedFlow(TemplateDTO template) { ProcessGroupDTO parentProcessGroup = new ProcessGroupDTO(); parentProcessGroup.setId(UUID.randomUUID().toString()); parentProcessGroup.setParentGroupId(UUID.randomUUID().toString()); parentProcessGroup.setName(template.getName()); parentProcessGroup.setContents(template.getSnippet()); NifiConnectionOrderVisitorCache cache = new NifiConnectionOrderVisitorCache(); Collection<ProcessGroupDTO> groups = NifiProcessUtil.getProcessGroups(parentProcessGroup); cache.add(parentProcessGroup); //add the snippet as its own process group if (template.getSnippet().getProcessors() != null) { //find the first processor and get its parent group id Optional<ProcessorDTO> firstProcessor = template.getSnippet().getProcessors().stream().findFirst(); if (firstProcessor.isPresent()) { String groupId = firstProcessor.get().getParentGroupId(); ProcessGroupDTO snippetGroup = new ProcessGroupDTO(); snippetGroup.setId(groupId); snippetGroup.setParentGroupId(template.getGroupId()); snippetGroup.setContents(template.getSnippet()); cache.add(snippetGroup); } } if (groups != null) { groups.stream().forEach(group -> cache.add(group)); } NifiVisitableProcessGroup visitableGroup = getFlowOrder(parentProcessGroup, cache, false); NifiFlowProcessGroup flow = new NifiFlowBuilder().build(visitableGroup); return flow; } public NifiFlowProcessGroup getTemplateFeedFlow(String templateId) { TemplateDTO template = restClient.templates().findById(templateId).orElseThrow(() -> new NifiComponentNotFoundException(templateId, NifiConstants.NIFI_COMPONENT_TYPE.TEMPLATE, null)); return getTemplateFeedFlow(template); } }