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.thinkbiganalytics.nifi.rest.model.flow.NiFiFlowProcessorConnection;
import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
/**
* Visit a NiFi processor and connect it to other processors
*
* @see NifiFlowVisitor
*/
public class NifiVisitableProcessor implements NifiVisitable {
private static final Logger log = LoggerFactory.getLogger(NifiVisitableProcessor.class);
private Set<NifiVisitableProcessor> sources; //parents
private Set<NifiVisitableProcessor> destinations; //children
/**
* The NiFi processor id
**/
private String id;
private Set<NiFiFlowProcessorConnection> sourceConnectionIdentifiers;
private Set<NiFiFlowProcessorConnection> destinationConnectionIdentifiers;
private ProcessorDTO dto;
public NifiVisitableProcessor(ProcessorDTO dto) {
this.dto = dto;
this.id = dto.getId();
}
/**
* visit the processor with the supplied visitor
*
* @param nifiVisitor the visitor
*/
@Override
public void accept(NifiFlowVisitor nifiVisitor) {
nifiVisitor.visitProcessor(this);
}
/**
* connect this processor to a incoming source processor
*
* @param dto the sorce processor
*/
public void addSource(NifiVisitableProcessor dto) {
getSources().add(dto);
}
/**
* connect this processor to a outgoing destination
*
* @param dto the destination processor
*/
public void addDestination(NifiVisitableProcessor dto) {
getDestinations().add(dto);
}
/**
* Return all processors that come directly before this processor
*
* @return the source processors connecting to this processor
*/
public Set<NifiVisitableProcessor> getSources() {
if (sources == null) {
sources = new HashSet<>();
}
return sources;
}
/**
* Return all the processors that connect after this processor
*
* @return the destination processors
*/
public Set<NifiVisitableProcessor> getDestinations() {
if (destinations == null) {
destinations = new HashSet<>();
}
return destinations;
}
/**
* Return the NiFi object representing this processor
*
* @return the nifi processor
*/
public ProcessorDTO getDto() {
return dto;
}
/**
* set the NiFi processor
*
* @param dto the NiFi processor
*/
public void setDto(ProcessorDTO dto) {
this.dto = dto;
}
/**
* Check to see if that this processor does not have any input/sources connected into it
*
* @return {@code true} if no processors are connected as sources to this processor, {@code false} if otherwise
*/
public boolean isStart() {
return !getDestinations().isEmpty() && getSources().isEmpty();
}
/**
* Check to see this processor is a leaft node meaning that this processor does not have any output/destinations connected from it
*
* @return {@code true} if no processors are connected as outputs from this processor, {@code false} if otherwise
*/
public boolean isEnd() {
return !getSources().isEmpty() && getDestinations().isEmpty();
}
/**
* Check to see if this processor Id matches another incoming processor
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NifiVisitableProcessor processor = (NifiVisitableProcessor) o;
return id.equals(processor.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
/***
* Print out the processor to log
*/
public void print() {
print(0);
}
/**
* Print out the processor to the log
*/
public void print(Integer level) {
log.info(level + ". " + getDto().getName());
Set<String> printed = new HashSet<>();
printed.add(this.getId());
Integer nextLevel = level + 1;
for (NifiVisitableProcessor child : getDestinations()) {
if (!child.containsDestination(this) && !child.containsDestination(child) && !child.equals(this) && !printed.contains(child.getId())) {
child.print(nextLevel);
printed.add(child.getId());
}
}
}
/**
* Check to see if this processor contains an incoming processor
*
* @param parent the processor to check for in this processors {@link this#getDestinations()}
* @return {@code true} if this processor already contains the incoming processor as its destination, {@code false} if not
*/
public boolean containsDestination(NifiVisitableProcessor parent) {
final String thisId = getDto().getId();
final String parentId = parent.getDto().getId();
NifiVisitableProcessor p = Iterables.tryFind(getDestinations(), new Predicate<NifiVisitableProcessor>() {
@Override
public boolean apply(NifiVisitableProcessor nifiVisitableProcessor) {
return nifiVisitableProcessor.getDto().getId().equalsIgnoreCase(thisId) || nifiVisitableProcessor.getDto().getId()
.equalsIgnoreCase(parentId);
}
}).orNull();
return p != null;
}
/**
* Return all the processors including the destinations walking thr graph of the {@link NifiVisitableProcessor#getDestinations()}
*
* @return all the processors including the destinations walking thr graph of the {@link NifiVisitableProcessor#getDestinations()}
*/
public Set<ProcessorDTO> getProcessors() {
return getProcessors(null);
}
/**
* Return all the processors including the destinations walking thr graph of the {@link NifiVisitableProcessor#getDestinations()}
*
* @param set of processors to inspect and retreive the NiFi processor dto from
* @return all the processors including the destinations walking thr graph of the {@link NifiVisitableProcessor#getDestinations()}
*/
public Set<ProcessorDTO> getProcessors(Set<NifiVisitableProcessor> set) {
if (set == null) {
set = new HashSet<>();
}
set.add(this);
for (NifiVisitableProcessor child : getDestinations()) {
if (!set.contains(child)) {
child.getProcessors(set);
}
}
Set<ProcessorDTO> p = new HashSet<>();
for (NifiVisitableProcessor x : set) {
p.add(x.getDto());
}
return p;
}
/**
* Return the id for this processor
*
* @return the id for the processor
*/
public String getId() {
return id;
}
/**
* add a connection as a source connection
*
* @param conn the source connection to this processor
*/
public void addSourceConnectionIdentifier(ConnectionDTO conn) {
getSourceConnectionIdentifiers().add(new NiFiFlowProcessorConnection(conn.getId(), conn.getName(), conn.getSelectedRelationships()));
}
/**
* add a connectionas a destination connection
*
* @param conn the destination connection from this processor
*/
public void addDestinationConnectionIdentifier(ConnectionDTO conn) {
NiFiFlowProcessorConnection destinationConnection = new NiFiFlowProcessorConnection(conn.getId(), conn.getName(), conn.getSelectedRelationships());
getDestinationConnectionIdentifiers().add(destinationConnection);
}
/**
* Return all connection ids marked as sources coming to this processor
*
* @return all connection ids marked as sources coming to this processor
*/
public Set<NiFiFlowProcessorConnection> getSourceConnectionIdentifiers() {
if (sourceConnectionIdentifiers == null) {
sourceConnectionIdentifiers = new HashSet<>();
}
return sourceConnectionIdentifiers;
}
/**
* Return all connection ids marked as destinations from this processor
*
* @return all connection ids marked as destinations from this processor
*/
public Set<NiFiFlowProcessorConnection> getDestinationConnectionIdentifiers() {
if (destinationConnectionIdentifiers == null) {
destinationConnectionIdentifiers = new HashSet<>();
}
return destinationConnectionIdentifiers;
}
}