use of org.apache.nifi.bootstrap.notification.NotificationValidationContext in project nifi by apache.
the class NotificationServiceManager method notify.
public void notify(final NotificationType type, final String subject, final String message) {
final List<ConfiguredNotificationService> configs = servicesByNotificationType.get(type);
if (configs == null || configs.isEmpty()) {
return;
}
for (final ConfiguredNotificationService config : configs) {
final NotificationService service = config.getService();
final AtomicInteger attemptCount = new AtomicInteger(0);
notificationExecutor.submit(new Runnable() {
@Override
public void run() {
// Check if the service is valid; if not, warn now so that users know this before they fail to receive notifications
final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config), variableRegistry);
final Collection<ValidationResult> validationResults = service.validate(validationContext);
final List<String> invalidReasons = new ArrayList<>();
for (final ValidationResult result : validationResults) {
if (!result.isValid()) {
invalidReasons.add(result.toString());
}
}
// If the service is valid, attempt to send the notification
boolean failure = false;
if (invalidReasons.isEmpty()) {
final NotificationContext context = buildNotificationContext(config);
try {
service.notify(context, type, subject, message);
logger.info("Successfully sent notification of type {} to {}", type, service);
} catch (final Throwable t) {
// keep running even if a Throwable is caught because we need to ensure that we are able to restart NiFi
logger.error("Failed to send notification of type {} to {} with Subject {} due to {}. Will ", type, service == null ? "Unknown Notification Service" : service.toString(), subject, t.toString());
logger.error("", t);
failure = true;
}
} else {
logger.warn("Notification Service {} is not valid for the following reasons: {}", service, invalidReasons);
failure = true;
}
final int attempts = attemptCount.incrementAndGet();
if (failure) {
if (attempts < maxAttempts) {
logger.info("After failing to send notification to {} {} times, will attempt again in 1 minute", service, attempts);
notificationExecutor.schedule(this, 1, TimeUnit.MINUTES);
} else {
logger.info("After failing to send notification of type {} to {} {} times, will no longer attempt to send notification", type, service, attempts);
}
}
}
});
if (NotificationType.NIFI_STOPPED.equals(type)) {
// we don't want to return before the notifier has had a chance to perform its task.
while (attemptCount.get() == 0) {
try {
Thread.sleep(1000L);
} catch (final InterruptedException ie) {
}
}
}
}
}
use of org.apache.nifi.bootstrap.notification.NotificationValidationContext in project nifi by apache.
the class NotificationServiceManager method loadNotificationServices.
/**
* Loads the Notification Services from the given XML configuration file.
*
* File is expected to have the following format:
*
* <pre>
* <services>
* <service>
* <id>service-identifier</id>
* <class>org.apache.nifi.MyNotificationService</class>
* <property name="My First Property">Property Value</property>
* </service>
* <service>
* <id>other-service</id>
* <class>org.apache.nifi.MyOtherNotificationService</class>
* <property name="Another Property">Property Value 2</property>
* </service>
* ...
* <service>
* <id>service-identifier-2</id>
* <class>org.apache.nifi.FinalNotificationService</class>
* <property name="Yet Another Property">3rd Prop Value</property>
* </service>
* </services>
* </pre>
*
* Note that as long as the file can be interpreted properly, a misconfigured service will result in a warning
* or error being logged and the service will be unavailable but will not prevent the rest of the services from loading.
*
* @param servicesFile the XML file to load services from.
* @throws IOException if unable to read from the given file
* @throws ParserConfigurationException if unable to parse the given file as XML properly
* @throws SAXException if unable to parse the given file properly
*/
public void loadNotificationServices(final File servicesFile) throws IOException, ParserConfigurationException, SAXException {
final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(false);
final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
final Map<String, ConfiguredNotificationService> serviceMap = new HashMap<>();
try (final InputStream fis = new FileInputStream(servicesFile);
final InputStream in = new BufferedInputStream(fis)) {
final Document doc = docBuilder.parse(new InputSource(in));
final List<Element> serviceElements = getChildElementsByTagName(doc.getDocumentElement(), "service");
logger.debug("Found {} service elements", serviceElements.size());
for (final Element serviceElement : serviceElements) {
final ConfiguredNotificationService config = createService(serviceElement);
final NotificationService service = config.getService();
if (service == null) {
// reason will have already been logged, so just move on.
continue;
}
final String id = service.getIdentifier();
if (serviceMap.containsKey(id)) {
logger.error("Found two different Notification Services configured with the same ID: '{}'. Loaded the first service.", id);
continue;
}
// Check if the service is valid; if not, warn now so that users know this before they fail to receive notifications
final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config), variableRegistry);
final Collection<ValidationResult> validationResults = service.validate(validationContext);
final List<String> invalidReasons = new ArrayList<>();
for (final ValidationResult result : validationResults) {
if (!result.isValid()) {
invalidReasons.add(result.toString());
}
}
if (!invalidReasons.isEmpty()) {
logger.warn("Configured Notification Service {} is not valid for the following reasons: {}", service, invalidReasons);
}
serviceMap.put(id, config);
}
}
logger.info("Successfully loaded the following {} services: {}", serviceMap.size(), serviceMap.keySet());
servicesById.clear();
servicesById.putAll(serviceMap);
}
Aggregations