package com.thinkbiganalytics.metadata.jobrepo.nifi.provenance;
/*-
* #%L
* thinkbig-operational-metadata-integration-service
* %%
* 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.ImmutableList;
import com.thinkbiganalytics.metadata.api.jobrepo.step.BatchStepExecution;
import com.thinkbiganalytics.nifi.rest.client.LegacyNifiRestClient;
import com.thinkbiganalytics.nifi.rest.client.NifiClientRuntimeException;
import com.thinkbiganalytics.nifi.rest.client.NifiConnectionException;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.web.api.dto.BulletinDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* process NiFi Bulletins
*/
@Component
public class NifiBulletinExceptionExtractor {
private static final Logger log = LoggerFactory.getLogger(NifiBulletinExceptionExtractor.class);
private static List<String> bulletinErrorLevels = ImmutableList.of("WARN", "ERROR");
@Autowired
private LegacyNifiRestClient nifiRestClient;
/**
* Extracts the identifier for the flow file from a bulletin message
*
* @param message The bulleting message
* @return A UUID as string
*/
public String getFlowFileUUIDFromBulletinMessage(String message) {
return StringUtils.substringBetween(message, "StandardFlowFileRecord[uuid=", ",");
}
/**
* associates the error message from Nifi to the step given
*
* @param stepExecution The step execution object
* @param flowFileId The UUID of the flow file to extract the error message from
* @param componentId The ID of the component posting the bulletin
* @return true if error messages were added to stepExecution, false otherwise
* @throws NifiConnectionException if cannot query Nifi
*/
public boolean addErrorMessagesToStep(BatchStepExecution stepExecution, String flowFileId, String componentId) throws NifiConnectionException {
if (StringUtils.isNotBlank(flowFileId) && StringUtils.isNotBlank(componentId)) {
List<BulletinDTO> bulletins = getProcessorBulletinsForComponentInFlowFile(flowFileId, componentId);
if (bulletins != null) {
String
msg =
bulletins.stream().filter(bulletinDTO -> bulletinErrorLevels.contains(bulletinDTO.getLevel().toUpperCase())).map(BulletinDTO::getMessage).collect(Collectors.joining(", "));
String exitMsg = StringUtils.isBlank(stepExecution.getExitMessage()) ? "" : stepExecution.getExitMessage() + "\n";
stepExecution.setExitMessage(exitMsg + msg);
return true;
}
}
return false;
}
/**
* queries for bulletins from component, in the flow file
*
* @param flowFileIds The collection UUID of the flow file to extract the error message from
* @return a list of bulletin objects that were posted by the component to the flow file
* @throws NifiConnectionException if cannot query Nifi
*/
public List<BulletinDTO> getErrorBulletinsForFlowFiles(Collection<String> flowFileIds) throws NifiConnectionException {
List<BulletinDTO> bulletins;
try {
String regexPattern = flowFileIds.stream().collect(Collectors.joining("|"));
bulletins = nifiRestClient.getBulletinsMatchingMessage(regexPattern);
log.info("Query for {} bulletins returned {} results ", regexPattern, bulletins.size());
if (bulletins != null && !bulletins.isEmpty()) {
bulletins = bulletins.stream().filter(bulletinDTO -> bulletinErrorLevels.contains(bulletinDTO.getLevel().toUpperCase())).collect(Collectors.toList());
}
return bulletins;
} catch (NifiClientRuntimeException e) {
if (e instanceof NifiConnectionException) {
throw e;
} else {
log.error("Error getProcessorBulletinsForFlowFiles ", flowFileIds);
}
}
return null;
}
/**
* queries for bulletins from component, in the flow file
*
* @param flowFileId The UUID of the flow file to extract the error message from
* @param componentId The ID of the component posting the bulletin
* @return a list of bulletin objects that were posted by the component to the flow file
* @throws NifiConnectionException if cannot query Nifi
*/
public List<BulletinDTO> getProcessorBulletinsForComponentInFlowFile(String flowFileId, String componentId) throws NifiConnectionException {
List<BulletinDTO> bulletins;
try {
bulletins = nifiRestClient.getProcessorBulletins(componentId);
return bulletins.stream().filter(bulletin -> flowFileId.equalsIgnoreCase(getFlowFileUUIDFromBulletinMessage(bulletin.getMessage()))).collect(Collectors.toList());
} catch (NifiClientRuntimeException e) {
if (e instanceof NifiConnectionException) {
throw e;
} else {
log.error("Error getProcessorBulletinsForComponentInFlowFile for flowfile {} and componentId: {} ", flowFileId, componentId);
}
}
return null;
}
}