package com.thinkbiganalytics.feedmgr.nifi;
/*-
* #%L
* thinkbig-feed-manager-controller
* %%
* 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.collect.Lists;
import com.thinkbiganalytics.feedmgr.nifi.cache.NifiFlowCache;
import com.thinkbiganalytics.feedmgr.rest.model.FeedMetadata;
import com.thinkbiganalytics.nifi.feedmgr.FeedCreationException;
import com.thinkbiganalytics.nifi.feedmgr.FeedRollbackException;
import com.thinkbiganalytics.nifi.feedmgr.InputOutputPort;
import com.thinkbiganalytics.nifi.feedmgr.TemplateCreationHelper;
import com.thinkbiganalytics.nifi.rest.client.LegacyNifiRestClient;
import com.thinkbiganalytics.nifi.rest.client.NifiClientRuntimeException;
import com.thinkbiganalytics.nifi.rest.client.NifiComponentNotFoundException;
import com.thinkbiganalytics.nifi.rest.client.layout.AlignProcessGroupComponents;
import com.thinkbiganalytics.nifi.rest.model.NiFiPropertyDescriptorTransform;
import com.thinkbiganalytics.nifi.rest.model.NifiError;
import com.thinkbiganalytics.nifi.rest.model.NifiProcessGroup;
import com.thinkbiganalytics.nifi.rest.model.NifiProcessorSchedule;
import com.thinkbiganalytics.nifi.rest.model.NifiProperty;
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.support.NifiFeedConstants;
import com.thinkbiganalytics.nifi.rest.support.NifiProcessUtil;
import com.thinkbiganalytics.nifi.rest.support.NifiPropertyUtil;
import org.apache.commons.lang3.StringUtils;
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 org.apache.nifi.web.api.dto.TemplateDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
/**
* Builds/updates a NiFi feed flow based on a NiFi template and a Feed Manager Feed.
*/
public class CreateFeedBuilder {
private static final Logger log = LoggerFactory.getLogger(CreateFeedBuilder.class);
LegacyNifiRestClient restClient;
TemplateCreationHelper templateCreationHelper;
private NifiFlowCache nifiFlowCache;
private String templateId;
private String category;
private String feedName;
private boolean enabled = true;
private FeedMetadata feedMetadata;
private PropertyExpressionResolver propertyExpressionResolver;
private String inputProcessorType;
private String reusableTemplateCategoryName = TemplateCreationHelper.REUSABLE_TEMPLATES_PROCESS_GROUP_NAME;
private boolean isReusableTemplate;
/**
* if true it will remove the versioned process group with the <feed> - timestamp
* if false it will keep thhe versioned process group
* These can be cleaned up later through the {@code CleanupStaleFeedRevisions} class
*/
private boolean removeInactiveVersionedProcessGroup;
/**
* List of Input / Output Port connections
*/
@Nonnull
private List<InputOutputPort> inputOutputPorts = Lists.newArrayList();
private NifiProcessGroup newProcessGroup = null;
private ProcessGroupDTO previousFeedProcessGroup = null;
private String version;
private List<NifiProperty> properties;
private NifiProcessorSchedule feedSchedule;
private NiFiPropertyDescriptorTransform propertyDescriptorTransform;
private List<NifiProperty> modifiedProperties;
private List<NifiError> errors = new ArrayList<>();
/**
* the category group in NiFi where this feed resides
**/
private ProcessGroupDTO categoryGroup;
protected CreateFeedBuilder(LegacyNifiRestClient restClient, NifiFlowCache nifiFlowCache, FeedMetadata feedMetadata, String templateId, PropertyExpressionResolver propertyExpressionResolver,
NiFiPropertyDescriptorTransform propertyDescriptorTransform) {
this.restClient = restClient;
this.nifiFlowCache = nifiFlowCache;
this.feedMetadata = feedMetadata;
this.category = feedMetadata.getCategory().getSystemName();
this.feedName = feedMetadata.getSystemFeedName();
this.templateId = templateId;
this.templateCreationHelper = new TemplateCreationHelper(this.restClient);
this.propertyExpressionResolver = propertyExpressionResolver;
this.propertyDescriptorTransform = propertyDescriptorTransform;
}
public static CreateFeedBuilder newFeed(LegacyNifiRestClient restClient, NifiFlowCache nifiFlowCache, FeedMetadata feedMetadata, String templateId,
PropertyExpressionResolver propertyExpressionResolver, NiFiPropertyDescriptorTransform propertyDescriptorTransform) {
return new CreateFeedBuilder(restClient, nifiFlowCache, feedMetadata, templateId, propertyExpressionResolver, propertyDescriptorTransform);
}
public CreateFeedBuilder feedSchedule(NifiProcessorSchedule feedSchedule) {
this.feedSchedule = feedSchedule;
return this;
}
public CreateFeedBuilder reusableTemplateCategoryName(String reusableTemplateCategoryName) {
this.reusableTemplateCategoryName = reusableTemplateCategoryName;
return this;
}
public CreateFeedBuilder enabled(boolean enabled) {
this.enabled = enabled;
return this;
}
public CreateFeedBuilder removeInactiveVersionedProcessGroup(boolean removeInactiveVersionedProcessGroup) {
this.removeInactiveVersionedProcessGroup = removeInactiveVersionedProcessGroup;
return this;
}
/**
* Adds the specified Input Port and Output Port connection to this feed.
*
* @param inputOutputPort the port connection
* @return this feed builder
*/
public CreateFeedBuilder addInputOutputPort(@Nonnull final InputOutputPort inputOutputPort) {
inputOutputPorts.add(inputOutputPort);
return this;
}
public CreateFeedBuilder inputProcessorType(String inputProcessorType) {
this.inputProcessorType = inputProcessorType;
return this;
}
public CreateFeedBuilder properties(List<NifiProperty> properties) {
this.properties = properties;
return this;
}
public CreateFeedBuilder version(String version) {
this.version = version;
return this;
}
public CreateFeedBuilder setReusableTemplate(boolean isReusableTemplate) {
this.isReusableTemplate = isReusableTemplate;
return this;
}
/**
* Build the NiFi flow instance
*
* @return an object indicating if the feed flow was successfully built or not
*/
public NifiProcessGroup build() throws FeedCreationException {
try {
newProcessGroup = null;
TemplateDTO template = restClient.getTemplateById(templateId);
if (template != null) {
//create the encompassing process group
String processGroupId = createProcessGroupForFeed();
if (StringUtils.isNotBlank(processGroupId)) {
//snapshot the existing controller services
templateCreationHelper.snapshotControllerServiceReferences();
//create the flow from the template
templateCreationHelper.instantiateFlowFromTemplate(processGroupId, templateId);
updatePortConnectionsForProcessGroup(processGroupId);
//mark the new services that were created as a result of creating the new flow from the template
templateCreationHelper.identifyNewlyCreatedControllerServiceReferences();
//match the properties incoming to the defined properties
updateProcessGroupProperties(processGroupId);
//Fetch the Feed Group now that it has the flow in it
ProcessGroupDTO entity = restClient.getProcessGroup(processGroupId, true, true);
ProcessorDTO input = fetchInputProcessorForProcessGroup(entity);
ProcessorDTO cleanupProcessor = NifiProcessUtil.findFirstProcessorsByType(NifiProcessUtil.getInputProcessors(entity),
"com.thinkbiganalytics.nifi.v2.metadata.TriggerCleanup");
List<ProcessorDTO> nonInputProcessors = NifiProcessUtil.getNonInputProcessors(entity);
List<NifiProperty> updatedControllerServiceProperties = new ArrayList<>();
//update any references to the controller services and try to assign the value to an enabled service if it is not already
if (input != null) {
updatedControllerServiceProperties.addAll(templateCreationHelper.updateControllerServiceReferences(Lists.newArrayList(input)));
}
if (cleanupProcessor != null) {
updatedControllerServiceProperties.addAll(templateCreationHelper.updateControllerServiceReferences(Collections.singletonList(cleanupProcessor)));
}
updatedControllerServiceProperties.addAll(templateCreationHelper.updateControllerServiceReferences(nonInputProcessors));
//refetch processors for updated errors
entity = restClient.getProcessGroup(processGroupId, true, true);
input = fetchInputProcessorForProcessGroup(entity);
nonInputProcessors = NifiProcessUtil.getNonInputProcessors(entity);
newProcessGroup = new NifiProcessGroup(entity, input, nonInputProcessors);
//Validate and if invalid Delete the process group
if (newProcessGroup.hasFatalErrors()) {
removeProcessGroup(entity);
// cleanupControllerServices();
newProcessGroup.setSuccess(false);
} else {
//update the input schedule
updateFeedSchedule(newProcessGroup, input);
//Cache the processorIds to the respective flowIds for availability in the ProvenanceReportingTask
NifiVisitableProcessGroup group = restClient.getFlowOrder(newProcessGroup.getProcessGroupEntity(), null);
NifiFlowProcessGroup
flow =
new NifiFlowBuilder().build(
group);
nifiFlowCache.updateFlow(feedMetadata, flow);
//disable all inputs
restClient.disableInputProcessors(newProcessGroup.getProcessGroupEntity().getId());
//mark everything else as running
templateCreationHelper.markProcessorsAsRunning(newProcessGroup);
//if desired start the input processor
if (input != null) {
if (enabled) {
markInputAsRunning(newProcessGroup, input);
///make the input/output ports in the category group as running
if (hasConnectionPorts()) {
templateCreationHelper.markConnectionPortsAsRunning(entity);
}
} else {
///make the input/output ports in the category group as running
if (hasConnectionPorts()) {
templateCreationHelper.markConnectionPortsAsRunning(entity);
}
markInputAsStopped(newProcessGroup, input);
}
}
if (newProcessGroup.hasFatalErrors()) {
rollback();
newProcessGroup.setRolledBack(true);
// cleanupControllerServices();
newProcessGroup.setSuccess(false);
}
List<NifiError> templateCreationErrors = templateCreationHelper.getErrors();
if (templateCreationErrors != null) {
errors.addAll(templateCreationErrors);
}
//add any global errors to the object
if (errors != null && !errors.isEmpty()) {
for (NifiError error : errors) {
newProcessGroup.addError(error);
if (error.isFatal()) {
newProcessGroup.setSuccess(false);
if (!newProcessGroup.isRolledBack()) {
rollback();
newProcessGroup.setRolledBack(true);
}
}
}
}
}
templateCreationHelper.cleanupControllerServices();
//fix the feed metadata controller service references
updateFeedMetadataControllerServiceReferences(updatedControllerServiceProperties);
//align items
log.info("Aligning Feed flows in NiFi ");
AlignProcessGroupComponents alignProcessGroupComponents = new AlignProcessGroupComponents(restClient.getNiFiRestClient(), entity.getParentGroupId());
alignProcessGroupComponents.autoLayout();
//if this is a new feedProcessGroup (i.e. new category), align the root level items also
//fetch the parent to get that id to align
if (previousFeedProcessGroup == null) {
log.info("This is the first feed created in the category {}. Aligning the categories. ", feedMetadata.getCategory().getSystemName());
new AlignProcessGroupComponents(restClient.getNiFiRestClient(), this.categoryGroup.getParentGroupId()).autoLayout();
}
}
}
return newProcessGroup;
} catch (NifiClientRuntimeException e) {
throw new FeedCreationException("Unable to create the feed [" + feedName + "]. " + e.getMessage(), e);
}
}
/**
* update feed metadata to point to the valid controller services
* @param updatedControllerServiceProperties
*/
private void updateFeedMetadataControllerServiceReferences(List<NifiProperty>updatedControllerServiceProperties){
//map of the previous to new service values
Map<String,String> controllerServiceChangeMap =updatedControllerServiceProperties.stream().collect(Collectors.toMap(p-> p.getProcessorNameTypeKey(), p->p.getValue(), (service1, service2) -> service1));
if(!updatedControllerServiceProperties.isEmpty()){
feedMetadata.getProperties().stream().filter(property -> controllerServiceChangeMap.containsKey(property.getProcessorNameTypeKey())).forEach(
(NifiProperty p) -> p.setValue(controllerServiceChangeMap.get(p.getProcessorNameTypeKey())));
}
}
public ProcessGroupDTO rollback() throws FeedRollbackException {
if (newProcessGroup != null) {
try {
removeProcessGroup(newProcessGroup.getProcessGroupEntity());
} catch (NifiClientRuntimeException e) {
log.error("Unable to delete the ProcessGroup on rollback {} ", e.getMessage());
}
}
String
parentGroupId =
newProcessGroup != null ? newProcessGroup.getProcessGroupEntity().getParentGroupId()
: (previousFeedProcessGroup != null ? previousFeedProcessGroup.getParentGroupId() : null);
try {
if (StringUtils.isNotBlank(parentGroupId)) {
ProcessGroupDTO feedGroup = restClient.getProcessGroupByName(parentGroupId, feedName);
//rename this group to be something else if for some reason we were not able to delete it
if (feedGroup != null) {
feedGroup.setName(feedGroup.getName() + ".rollback - " + new Date().getTime());
restClient.updateProcessGroup(feedGroup);
feedGroup = restClient.getProcessGroupByName(parentGroupId, feedName);
}
//attempt to reset the last version back to this feed process group... do so only if there is no feed group with this name
//there shouldn't be as we should have deleted it above
if (feedGroup == null) {
if (previousFeedProcessGroup != null) {
ProcessGroupDTO entity = restClient.getProcessGroup(previousFeedProcessGroup.getId(), false, false);
if (entity != null) {
entity.setName(feedName);
entity = restClient.updateProcessGroup(entity);
updatePortConnectionsForProcessGroup(entity.getId());
//disable all inputs
restClient.disableInputProcessors(entity.getId());
//mark everything else as running
restClient.markProcessorGroupAsRunning(entity);
if (hasConnectionPorts()) {
templateCreationHelper.markConnectionPortsAsRunning(entity);
}
//Set the state correctly for the inputs
if (enabled) {
restClient.setInputProcessorState(entity.getId(),
inputProcessorType, NifiProcessUtil.PROCESS_STATE.RUNNING);
} else {
restClient.setInputProcessorState(entity.getId(),
inputProcessorType, NifiProcessUtil.PROCESS_STATE.STOPPED);
}
return entity;
}
}
}
}
} catch (Exception e) {
throw new FeedRollbackException("Unable to rollback feed [" + feedName + "] with Parent Group Id of [" + parentGroupId + "] " + e.getMessage(), e);
}
return null;
}
private void connectFeedToReusableTemplate(String feedGroupId) throws NifiComponentNotFoundException {
ProcessGroupDTO reusableTemplateCategory = restClient.getProcessGroupByName("root", reusableTemplateCategoryName);
ProcessGroupDTO feedProcessGroup = restClient.getProcessGroup(feedGroupId, false, false);
String feedCategoryId = feedProcessGroup.getParentGroupId();
if (reusableTemplateCategory == null) {
throw new NifiClientRuntimeException("Unable to find the Reusable Template Group. Please ensure NiFi has the 'reusable_templates' processgroup and appropriate reusable flow for this feed."
+ " You may need to import the base reusable template for this feed.");
}
String reusableTemplateCategoryGroupId = reusableTemplateCategory.getId();
for (InputOutputPort port : inputOutputPorts) {
restClient.connectFeedToGlobalTemplate(feedGroupId, port.getOutputPortName(), feedCategoryId, reusableTemplateCategoryGroupId, port.getInputPortName());
}
}
private void ensureInputPortsForReuseableTemplate(String feedGroupId) throws NifiComponentNotFoundException {
ProcessGroupDTO template = restClient.getProcessGroup(feedGroupId, false, false);
String categoryId = template.getParentGroupId();
restClient.createReusableTemplateInputPort(categoryId, feedGroupId);
}
private boolean hasConnectionPorts() {
return !inputOutputPorts.isEmpty() || isReusableTemplate;
}
private ProcessorDTO fetchInputProcessorForProcessGroup(ProcessGroupDTO entity) {
// Find first processor by type
final List<ProcessorDTO> inputProcessors = NifiProcessUtil.getInputProcessors(entity);
final ProcessorDTO input = Optional.ofNullable(NifiProcessUtil.findFirstProcessorsByType(inputProcessors, inputProcessorType))
.orElseGet(() -> inputProcessors.stream()
.filter(processor -> !processor.getType().equals(NifiProcessUtil.CLEANUP_TYPE))
.findFirst()
.orElse(null)
);
// Update cached type
if (input != null) {
inputProcessorType = input.getType();
}
return input;
}
private void updatePortConnectionsForProcessGroup(String processGroupId) throws NifiComponentNotFoundException {
//if the feed has an outputPort that should go to a reusable Flow then make those connections
if (!inputOutputPorts.isEmpty()) {
connectFeedToReusableTemplate(processGroupId);
}
if (isReusableTemplate) {
ensureInputPortsForReuseableTemplate(processGroupId);
}
}
private String createProcessGroupForFeed() throws FeedCreationException {
//create Category Process group
String processGroupId = null;
this.categoryGroup = restClient.getProcessGroupByName("root", category);
if (categoryGroup == null) {
try {
ProcessGroupDTO group = restClient.createProcessGroup(category);
this.categoryGroup = group;
} catch (Exception e) {
//Swallow exception... it will be handled later
}
}
if (this.categoryGroup == null) {
throw new FeedCreationException("Unable to get or create the Process group for the Category " + category
+ ". Error occurred while creating instance of template " + templateId + " for Feed "
+ feedName);
}
//1 create the processGroup
//check to see if the feed exists... if so version off the old group and create a new group with this feed
ProcessGroupDTO feedGroup = restClient.getProcessGroupByName(this.categoryGroup.getId(), feedName);
if (feedGroup != null) {
try {
previousFeedProcessGroup = feedGroup;
templateCreationHelper.versionProcessGroup(feedGroup);
} catch (Exception e) {
throw new FeedCreationException("Previous version of the feed " + feedName
+ " was found. Error in attempting to version the previous feed. Please go into Nifi and address any issues with the Feeds Process Group", e);
}
}
ProcessGroupDTO group = restClient.createProcessGroup(this.categoryGroup.getId(), feedName);
if (group != null) {
processGroupId = group.getId();
}
return processGroupId;
}
/**
* removes the {@code previousFeedProcessGroup} from nifi
*/
public void checkAndRemoveVersionedProcessGroup() {
if (this.removeInactiveVersionedProcessGroup && previousFeedProcessGroup != null) {
removeProcessGroup(previousFeedProcessGroup);
}
}
/**
* Removes a given processGroup from NiFi if nothing is in its queue
*/
private void removeProcessGroup(ProcessGroupDTO processGroupDTO) {
if (processGroupDTO != null) {
try {
//validate if nothing is in the queue then remove it
Optional<ProcessGroupStatusDTO> statusDTO = restClient.getNiFiRestClient().processGroups().getStatus(processGroupDTO.getId());
if (statusDTO.isPresent() && propertyDescriptorTransform.getQueuedCount(statusDTO.get()).equalsIgnoreCase("0")) {
//get connections linking to this group, delete them
Set<ConnectionDTO> connectionDTOs = restClient.getProcessGroupConnections(processGroupDTO.getParentGroupId());
if (connectionDTOs == null) {
connectionDTOs = new HashSet<>();
}
Set<ConnectionDTO>
versionedConnections =
connectionDTOs.stream().filter(connectionDTO -> connectionDTO.getDestination().getGroupId().equalsIgnoreCase(processGroupDTO.getId()) || connectionDTO.getSource().getGroupId()
.equalsIgnoreCase(processGroupDTO.getId()))
.collect(Collectors.toSet());
restClient.deleteProcessGroupAndConnections(processGroupDTO, versionedConnections);
log.info("removed the versioned processgroup {} ", processGroupDTO.getName());
} else {
log.info("Unable to remove the versioned processgroup {} ", processGroupDTO.getName());
}
} catch (Exception e) {
log.error("Unable to remove the versioned processgroup {} ", processGroupDTO.getName(), e);
}
}
}
/**
* Updates a process groups properties
*/
private void updateProcessGroupProperties(String processGroupId) throws FeedCreationException {
List<NifiProperty> propertiesToUpdate = restClient.getPropertiesForProcessGroup(processGroupId);
//get the Root processGroup
ProcessGroupDTO rootProcessGroup = restClient.getRootProcessGroup();
//get this process group
ProcessGroupDTO activeProcessGroupName = restClient.getProcessGroup(processGroupId, false, false);
modifiedProperties = new ArrayList<>();
//resolve the static properties
//first fill in any properties with static references
List<NifiProperty> modifiedStaticProperties = propertyExpressionResolver.resolveStaticProperties(propertiesToUpdate);
// now apply any of the incoming metadata properties to this
List<NifiProperty> modifiedFeedMetadataProperties = NifiPropertyUtil.matchAndSetPropertyValues(rootProcessGroup.getName(),
activeProcessGroupName.getName(),
propertiesToUpdate, properties);
modifiedProperties.addAll(modifiedStaticProperties);
modifiedProperties.addAll(modifiedFeedMetadataProperties);
restClient.updateProcessGroupProperties(modifiedProperties);
}
private void markInputAsRunning(NifiProcessGroup newProcessGroup, ProcessorDTO input) {
setInputProcessorState(newProcessGroup, input, NifiProcessUtil.PROCESS_STATE.RUNNING);
}
private void markInputAsStopped(NifiProcessGroup newProcessGroup, ProcessorDTO input) {
setInputProcessorState(newProcessGroup, input, NifiProcessUtil.PROCESS_STATE.STOPPED);
}
private void setInputProcessorState(NifiProcessGroup newProcessGroup, ProcessorDTO input, NifiProcessUtil.PROCESS_STATE state) {
setInputProcessorState(newProcessGroup.getProcessGroupEntity(),
input, state);
}
/**
* Sets the First processors in the {@code processGroup} matching the passed in {@code input} ProcessorType to the passed in {@code state}
* If the input ins null it will use the default {@code inputType} supplied from the builder
*
* @param processGroup the group which should be inspected for the input processors
* @param input the processor type to match when finding the correct input
* @param state the state to set the matched input processor
*/
private void setInputProcessorState(ProcessGroupDTO processGroup, ProcessorDTO input, NifiProcessUtil.PROCESS_STATE state) {
try {
if (input != null && (StringUtils.isBlank(inputProcessorType) || !inputProcessorType.equalsIgnoreCase(input.getType()))) {
inputProcessorType = input.getType();
}
restClient.setInputProcessorState(processGroup.getId(),
inputProcessorType, state);
} catch (Exception error) {
String
errorMsg =
"Unable to mark group as " + state + " for " + input.getName() + "("
+ inputProcessorType + ").";
newProcessGroup
.addError(newProcessGroup.getProcessGroupEntity().getId(), input.getId(), NifiError.SEVERITY.WARN,
errorMsg, "Process State");
newProcessGroup.setSuccess(false);
}
}
private void updateFeedSchedule(NifiProcessGroup newProcessGroup, ProcessorDTO input) {
if (feedSchedule != null && input != null) {
String strategy = feedSchedule.getSchedulingStrategy();
String schedule = feedSchedule.getSchedulingPeriod();
//if the input is of type TriggerFeed then make the schedule for that processor Timer Driven in the flow
if (inputProcessorType.equalsIgnoreCase(NifiFeedConstants.TRIGGER_FEED_PROCESSOR_CLASS)) {
strategy = NifiFeedConstants.SCHEDULE_STRATEGIES.TIMER_DRIVEN.name();
schedule = NifiFeedConstants.DEFAULT_TIGGER_FEED_PROCESSOR_SCHEDULE;
}
input.getConfig().setSchedulingPeriod(schedule);
input.getConfig().setSchedulingStrategy(strategy);
input.getConfig().setConcurrentlySchedulableTaskCount(feedSchedule.getConcurrentTasks());
try {
restClient.updateProcessor(input);
} catch (Exception e) {
String
errorMsg =
"Unable set Scheduling Information for feed " + input.getName() + " on " + input.getType() + ". Please check to make sure you set the Timer or Cron Expression correctly";
newProcessGroup.addError(input.getParentGroupId(), input.getId(), NifiError.SEVERITY.WARN, errorMsg, "Schedule");
newProcessGroup.setSuccess(false);
}
}
}
}