Search in sources :

Example 1 with NotificationService

use of org.apache.nifi.bootstrap.notification.NotificationService 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) {
                }
            }
        }
    }
}
Also used : NotificationValidationContext(org.apache.nifi.bootstrap.notification.NotificationValidationContext) NotificationService(org.apache.nifi.bootstrap.notification.NotificationService) ValidationResult(org.apache.nifi.components.ValidationResult) NotificationValidationContext(org.apache.nifi.bootstrap.notification.NotificationValidationContext) ValidationContext(org.apache.nifi.components.ValidationContext) NotificationContext(org.apache.nifi.bootstrap.notification.NotificationContext) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Collection(java.util.Collection) ArrayList(java.util.ArrayList) NodeList(org.w3c.dom.NodeList) List(java.util.List)

Example 2 with NotificationService

use of org.apache.nifi.bootstrap.notification.NotificationService in project nifi by apache.

the class NotificationServiceManager method buildNotificationContext.

private NotificationContext buildNotificationContext(final ConfiguredNotificationService config) {
    return new NotificationContext() {

        @Override
        public PropertyValue getProperty(final PropertyDescriptor descriptor) {
            final PropertyDescriptor fullPropDescriptor = config.getService().getPropertyDescriptor(descriptor.getName());
            if (fullPropDescriptor == null) {
                return null;
            }
            String configuredValue = config.getProperties().get(fullPropDescriptor.getName());
            if (configuredValue == null) {
                configuredValue = fullPropDescriptor.getDefaultValue();
            }
            return new StandardPropertyValue(configuredValue, null, variableRegistry);
        }

        @Override
        public Map<PropertyDescriptor, String> getProperties() {
            final Map<PropertyDescriptor, String> props = new HashMap<>();
            final Map<String, String> configuredProps = config.getProperties();
            final NotificationService service = config.getService();
            final List<PropertyDescriptor> configuredPropertyDescriptors = new ArrayList<>(service.getPropertyDescriptors());
            // This is needed to capture all dynamic properties
            configuredProps.forEach((key, value) -> {
                PropertyDescriptor propertyDescriptor = config.service.getPropertyDescriptor(key);
                props.put(config.service.getPropertyDescriptor(key), value);
                configuredPropertyDescriptors.remove(propertyDescriptor);
            });
            for (final PropertyDescriptor descriptor : configuredPropertyDescriptors) {
                props.put(descriptor, descriptor.getDefaultValue());
            }
            return props;
        }
    };
}
Also used : NotificationContext(org.apache.nifi.bootstrap.notification.NotificationContext) PropertyDescriptor(org.apache.nifi.components.PropertyDescriptor) HashMap(java.util.HashMap) StandardPropertyValue(org.apache.nifi.attribute.expression.language.StandardPropertyValue) ArrayList(java.util.ArrayList) NotificationService(org.apache.nifi.bootstrap.notification.NotificationService)

Example 3 with NotificationService

use of org.apache.nifi.bootstrap.notification.NotificationService in project nifi by apache.

the class NotificationServiceManager method createService.

/**
 * Creates a Notification Service and initializes it. Then returns the service and its configured properties
 *
 * @param serviceElement the XML element from which to build the Notification Service
 * @return a Tuple with the NotificationService as the key and the configured properties as the value, or <code>null</code> if
 *         unable to create the service
 */
private ConfiguredNotificationService createService(final Element serviceElement) {
    final Element idElement = getChild(serviceElement, "id");
    if (idElement == null) {
        logger.error("Found configuration for Notification Service with no 'id' element; this service cannot be referenced so it will not be loaded");
        return null;
    }
    final String serviceId = idElement.getTextContent().trim();
    logger.debug("Loading Notification Service with ID {}", serviceId);
    final Element classElement = getChild(serviceElement, "class");
    if (classElement == null) {
        logger.error("Found configuration for Notification Service with no 'class' element; Service ID is '{}'. This service annot be loaded", serviceId);
        return null;
    }
    final String className = classElement.getTextContent().trim();
    final Class<?> clazz;
    try {
        clazz = Class.forName(className);
    } catch (final Exception e) {
        logger.error("Found configuration for Notification Service with ID '{}' and Class '{}' but could not load class.", serviceId, className);
        logger.error("", e);
        return null;
    }
    if (!NotificationService.class.isAssignableFrom(clazz)) {
        logger.error("Found configuration for Notification Service with ID '{}' and Class '{}' but class is not a Notification Service.", serviceId, className);
        return null;
    }
    final Object serviceObject;
    try {
        serviceObject = clazz.newInstance();
    } catch (final Exception e) {
        logger.error("Found configuration for Notification Service with ID '{}' and Class '{}' but could not instantiate Notification Service.", serviceId, className);
        logger.error("", e);
        return null;
    }
    final Map<String, String> propertyValues = new HashMap<>();
    final List<Element> propertyElements = getChildElementsByTagName(serviceElement, "property");
    for (final Element propertyElement : propertyElements) {
        final String propName = propertyElement.getAttribute("name");
        if (propName == null || propName.trim().isEmpty()) {
            logger.warn("Found configuration for Notification Service with ID '{}' that has property value configured but no name for the property.", serviceId);
            continue;
        }
        final String propValue = propertyElement.getTextContent().trim();
        propertyValues.put(propName, propValue);
    }
    final NotificationService service = (NotificationService) serviceObject;
    try {
        service.initialize(new NotificationInitializationContext() {

            @Override
            public PropertyValue getProperty(final PropertyDescriptor descriptor) {
                final String propName = descriptor.getName();
                String value = propertyValues.get(propName);
                if (value == null) {
                    value = descriptor.getDefaultValue();
                }
                return new StandardPropertyValue(value, null, variableRegistry);
            }

            @Override
            public Map<String, String> getAllProperties() {
                return Collections.unmodifiableMap(propertyValues);
            }

            @Override
            public String getIdentifier() {
                return serviceId;
            }
        });
    } catch (final Exception e) {
        logger.error("Failed to load Notification Service with ID '{}'", serviceId);
        logger.error("", e);
    }
    return new ConfiguredNotificationService(service, propertyValues);
}
Also used : PropertyDescriptor(org.apache.nifi.components.PropertyDescriptor) HashMap(java.util.HashMap) Element(org.w3c.dom.Element) StandardPropertyValue(org.apache.nifi.attribute.expression.language.StandardPropertyValue) PropertyValue(org.apache.nifi.components.PropertyValue) StandardPropertyValue(org.apache.nifi.attribute.expression.language.StandardPropertyValue) NotificationService(org.apache.nifi.bootstrap.notification.NotificationService) IOException(java.io.IOException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) SAXException(org.xml.sax.SAXException) NotificationInitializationContext(org.apache.nifi.bootstrap.notification.NotificationInitializationContext) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with NotificationService

use of org.apache.nifi.bootstrap.notification.NotificationService 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>
 * &lt;services&gt;
 *   &lt;service&gt;
 *     &lt;id&gt;service-identifier&lt;/id&gt;
 *     &lt;class&gt;org.apache.nifi.MyNotificationService&lt;/class&gt;
 *     &lt;property name="My First Property"&gt;Property Value&lt;/property&gt;
 *   &lt;/service&gt;
 *   &lt;service&gt;
 *     &lt;id&gt;other-service&lt;/id&gt;
 *     &lt;class&gt;org.apache.nifi.MyOtherNotificationService&lt;/class&gt;
 *     &lt;property name="Another Property"&gt;Property Value 2&lt;/property&gt;
 *   &lt;/service&gt;
 *   ...
 *   &lt;service&gt;
 *     &lt;id&gt;service-identifier-2&lt;/id&gt;
 *     &lt;class&gt;org.apache.nifi.FinalNotificationService&lt;/class&gt;
 *     &lt;property name="Yet Another Property"&gt;3rd Prop Value&lt;/property&gt;
 *   &lt;/service&gt;
 * &lt;/services&gt;
 * </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);
}
Also used : InputSource(org.xml.sax.InputSource) DocumentBuilderFactory(javax.xml.parsers.DocumentBuilderFactory) HashMap(java.util.HashMap) NotificationValidationContext(org.apache.nifi.bootstrap.notification.NotificationValidationContext) BufferedInputStream(java.io.BufferedInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) Element(org.w3c.dom.Element) ArrayList(java.util.ArrayList) NotificationService(org.apache.nifi.bootstrap.notification.NotificationService) Document(org.w3c.dom.Document) ValidationResult(org.apache.nifi.components.ValidationResult) FileInputStream(java.io.FileInputStream) NotificationValidationContext(org.apache.nifi.bootstrap.notification.NotificationValidationContext) ValidationContext(org.apache.nifi.components.ValidationContext) DocumentBuilder(javax.xml.parsers.DocumentBuilder) BufferedInputStream(java.io.BufferedInputStream)

Aggregations

NotificationService (org.apache.nifi.bootstrap.notification.NotificationService)4 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 StandardPropertyValue (org.apache.nifi.attribute.expression.language.StandardPropertyValue)2 NotificationContext (org.apache.nifi.bootstrap.notification.NotificationContext)2 NotificationValidationContext (org.apache.nifi.bootstrap.notification.NotificationValidationContext)2 PropertyDescriptor (org.apache.nifi.components.PropertyDescriptor)2 ValidationContext (org.apache.nifi.components.ValidationContext)2 ValidationResult (org.apache.nifi.components.ValidationResult)2 Element (org.w3c.dom.Element)2 BufferedInputStream (java.io.BufferedInputStream)1 FileInputStream (java.io.FileInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 Collection (java.util.Collection)1 List (java.util.List)1 Map (java.util.Map)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 DocumentBuilder (javax.xml.parsers.DocumentBuilder)1 DocumentBuilderFactory (javax.xml.parsers.DocumentBuilderFactory)1