package com.thinkbiganalytics.nifi.rest.model.visitor;
/*-
* #%L
* thinkbig-nifi-flow-visitor-model
* %%
* 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.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Represents the NiFi Process Group that can be visited and linked building a graph of connecting parents and children {@link NifiVisitableProcessor}
* These are built from the {@link NifiFlowVisitor}
*/
public class NifiVisitableProcessGroup implements NifiVisitable {
/**
* all the processors visited in this group
*/
public Set<NifiVisitableProcessor> processors;
/**
* the Nifi process group
*/
private ProcessGroupDTO dto;
/**
* The parent process group for which this process group resides
*/
private ProcessGroupDTO parentProcessGroup;
/**
* the starting processors in this group which dont have any source connections in front of them
*/
private Set<NifiVisitableProcessor> startingProcessors;
/**
* the ending processors in this group that dont have any destination connections from them
*/
private Set<NifiVisitableProcessor> endingProcessors;
/**
* Map of the output port id to set of connecting processor ids
*/
private Map<String, Set<NifiVisitableProcessor>> outputPortProcessors;
/**
* Map of the input port id to set of connecting processor ids
*/
private Map<String, Set<NifiVisitableProcessor>> inputPortProcessors;
private Set<ConnectionDTO> connections;
/**
* Create a new visitable group from a given NiFi process group
*
* @param dto a NiFi process group
*/
public NifiVisitableProcessGroup(ProcessGroupDTO dto) {
this.dto = dto;
startingProcessors = new HashSet<>();
endingProcessors = new HashSet<>();
outputPortProcessors = new HashMap<>();
inputPortProcessors = new HashMap<>();
processors = new HashSet<>();
connections = new HashSet<>();
if (dto.getContents() != null) {
this.connections = dto.getContents().getConnections();
}
}
/**
* Return a visitable processor, first looking at those that have been visited already by this process group, if not it will create a new one.
*
* @param nifiVisitor the visitor
* @param processorDTO the processor to find
* @return a visitable processor, wrapping the incoming processordto, to process or link to as a source/destination
*/
private NifiVisitableProcessor getOrCreateProcessor(NifiFlowVisitor nifiVisitor, ProcessorDTO processorDTO) {
NifiVisitableProcessor processor = nifiVisitor.getProcessor(processorDTO.getId());
if (processor == null) {
processor = new NifiVisitableProcessor(processorDTO);
addProcessor(processor);
}
return processor;
}
/**
* Return a visitable process group first looking at those that have been visited already by this parent process group, if not it will create a new one.
*
* @param nifiVisitor the visitor
* @param processGroupDTO the group to find
* @return the visitable process group wrapping the incoming processgroup
*/
private NifiVisitableProcessGroup getOrCreateProcessGroup(NifiFlowVisitor nifiVisitor, ProcessGroupDTO processGroupDTO) {
NifiVisitableProcessGroup group = nifiVisitor.getProcessGroup(processGroupDTO.getId());
if (group == null) {
group = new NifiVisitableProcessGroup(processGroupDTO);
}
return group;
}
/**
* Return the parent process group for this group
*
* @return the parent process group for this group
*/
public ProcessGroupDTO getParentProcessGroup() {
return parentProcessGroup;
}
/**
* set the parent process group
*
* @param parentProcessGroup the group that is the parent group to this group
*/
public void setParentProcessGroup(ProcessGroupDTO parentProcessGroup) {
this.parentProcessGroup = parentProcessGroup;
}
/**
* Visit this process group using the supplied visitor
*
* @param nifiVisitor the visitor
*/
@Override
public void accept(NifiFlowVisitor nifiVisitor) {
if (dto.getContents() != null) {
if (dto.getContents().getProcessors() != null) {
for (ProcessorDTO processorDTO : dto.getContents().getProcessors()) {
NifiVisitableProcessor processor = getOrCreateProcessor(nifiVisitor, processorDTO);
nifiVisitor.visitProcessor(processor);
}
}
if (dto.getContents().getProcessGroups() != null) {
for (ProcessGroupDTO processGroupDTO : dto.getContents().getProcessGroups()) {
if (processGroupDTO != null) {
nifiVisitor.visitProcessGroup(getOrCreateProcessGroup(nifiVisitor, processGroupDTO));
}
}
}
if (dto.getContents().getConnections() != null) {
for (ConnectionDTO connectionDTO : dto.getContents().getConnections()) {
nifiVisitor.visitConnection(new NifiVisitableConnection(this, connectionDTO));
}
}
populateStartingAndEndingProcessors();
}
}
/**
* Return the NiFi ProcessGroup that this class wraps
*
* @return the NiFi process group item
*/
public ProcessGroupDTO getDto() {
return dto;
}
/**
* After visiting a processor, add it to the cache of processors referenced by this process group
*
* @param processor the processor that has been visited
*/
public void addProcessor(NifiVisitableProcessor processor) {
processors.add(processor);
}
/**
* Return a set of all the processors that dont have any incoming source connections
*
* @return a set of all the processors that dont have any incoming source connections
*/
public Set<NifiVisitableProcessor> getStartingProcessors() {
return startingProcessors;
}
/**
* Return a set of all the ending/leaf processors that dont have destination connections coming from them
*
* @return a set of all the ending/leaf processors that dont have destination connections coming from them
*/
public Set<NifiVisitableProcessor> getEndingProcessors() {
return endingProcessors;
}
/**
* Return the connection, if any, matching the incoming source connectionSourceId
*
* @param connectionSourceId the unique id for the connection source to find
* @return a connection matching the incoming connectionSourceId, or Null if not found
*/
public ConnectionDTO getConnectionMatchingSourceId(final String connectionSourceId) {
if (connections != null) {
return Iterables.tryFind(connections, new Predicate<ConnectionDTO>() {
@Override
public boolean apply(ConnectionDTO connection) {
return connection.getSource() != null && connection.getSource().getId().equals(connectionSourceId);
}
}).orNull();
}
return null;
}
/**
* Return the connection, if any, matching the incoming destination connectionDestinationId
*
* @param connectionDestinationId the unique id for the connection destination to find
* @return a connection matching the incoming connectionDestinationId, or Null if not found
*/
public ConnectionDTO getConnectionMatchingDestinationId(final String connectionDestinationId) {
if (connections != null) {
return Iterables.tryFind(connections, new Predicate<ConnectionDTO>() {
@Override
public boolean apply(ConnectionDTO connection) {
return connection.getDestination() != null && connection.getDestination().getId().equals(connectionDestinationId);
}
}).orNull();
}
return null;
}
/**
* populate the processors source/sink processors
*/
private void populateStartingAndEndingProcessors() {
for (NifiVisitableProcessor processor : processors) {
if (processor.isStart()) {
startingProcessors.add(processor);
}
if (processor.isEnd()) {
endingProcessors.add(processor);
}
}
}
/**
* Return the processors that are attached to input ports
*
* @return processors attaached to a specific input port
*/
public Set<NifiVisitableProcessor> getInputPortProcessors(String inputPortId) {
return inputPortProcessors.get(inputPortId);
}
/**
* add the input port and processor to the map
*
* @param id the id of the input port
* @param inputPortProcessor the processor connected to the input port
*/
public void addInputPortProcessor(String id, NifiVisitableProcessor inputPortProcessor) {
if (!this.inputPortProcessors.containsKey(id)) {
this.inputPortProcessors.put(id, new HashSet<>());
}
this.inputPortProcessors.get(id).add(inputPortProcessor);
}
/**
* Return the set of output port processors
*
* @param outputPortId the output port id
* @return the processors connected to the supplied output port
*/
public Set<NifiVisitableProcessor> getOutputPortProcessors(String outputPortId) {
return outputPortProcessors.get(outputPortId);
}
/**
* Return the processor connected to the supplied output port
*
* @return the processor
*/
public NifiVisitableProcessor getOutputPortProcessor(String connectionSourceId) {
if (outputPortProcessors.containsKey(connectionSourceId)) {
return Lists.newArrayList(outputPortProcessors.get(connectionSourceId)).get(0);
}
return null;
}
/**
* Add a processor connected to the supplied output port id
*
* @param id the output port id
* @param outputPortProcessor the processor attached to this output port
*/
public void addOutputPortProcessor(String id, NifiVisitableProcessor outputPortProcessor) {
if (!this.outputPortProcessors.containsKey(id)) {
this.outputPortProcessors.put(id, new HashSet<>());
}
this.outputPortProcessors.get(id).add(outputPortProcessor);
}
/**
* Return the map of input port id to processors
*
* @return the map of input port id to processors
*/
public Map<String, Set<NifiVisitableProcessor>> getInputPortProcessors() {
return inputPortProcessors;
}
/**
* Return the map of output port id to processors
*
* @return the map of output port id to processors
*/
public Map<String, Set<NifiVisitableProcessor>> getOutputPortProcessors() {
return outputPortProcessors;
}
/**
* Return all the visited processors
*
* @return all the visited processors
*/
public Set<NifiVisitableProcessor> getProcessors() {
return processors;
}
/**
* Return all the all connections under this process group
*
* @return all the all connections under this process group
*/
public Set<ConnectionDTO> getConnections() {
return connections;
}
}