1 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
3 import com.google.common.annotations.VisibleForTesting;
4 import io.fd.honeycomb.v3po.notification.NotificationCollector;
5 import io.fd.honeycomb.v3po.notification.impl.NotificationProducerRegistry;
6 import java.io.IOException;
8 import java.util.stream.Collectors;
9 import javax.xml.stream.XMLOutputFactory;
10 import javax.xml.stream.XMLStreamException;
11 import javax.xml.stream.XMLStreamWriter;
12 import javax.xml.transform.dom.DOMResult;
13 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
14 import org.opendaylight.controller.config.util.xml.XmlUtil;
15 import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
16 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
17 import org.opendaylight.controller.sal.core.api.model.SchemaService;
18 import org.opendaylight.netconf.notifications.NetconfNotification;
19 import org.opendaylight.netconf.notifications.NotificationPublisherRegistration;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.streams.StreamBuilder;
22 import org.opendaylight.yangtools.concepts.ListenerRegistration;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
25 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
26 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
27 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Element;
35 public class HoneycombNotificationToNetconfTranslatorModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombNotificationToNetconfTranslatorModule {
37 private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotificationToNetconfTranslatorModule.class);
39 public HoneycombNotificationToNetconfTranslatorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
40 super(identifier, dependencyResolver);
43 public HoneycombNotificationToNetconfTranslatorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.HoneycombNotificationToNetconfTranslatorModule oldModule, java.lang.AutoCloseable oldInstance) {
44 super(identifier, dependencyResolver, oldModule, oldInstance);
48 public void customValidation() {
49 JmxAttributeValidationException.checkCondition(!getNetconfStreamName().isEmpty(),
50 "Stream name cannot be empty", netconfStreamNameJmxAttribute);
51 JmxAttributeValidationException.checkCondition(!getNetconfStreamDescription().isEmpty(),
52 "Stream description cannot be empty", netconfStreamDescriptionJmxAttribute);
56 public java.lang.AutoCloseable createInstance() {
57 final SchemaService schemaService = getSchemaServiceDependency();
58 final StreamNameType streamType = new StreamNameType(getNetconfStreamName());
59 final NotificationCollector hcNotificationCollector = getHoneycombNotificationCollectorDependency();
61 // Register as NETCONF notification publisher under configured name
62 final NotificationPublisherRegistration netconfNotificationProducerReg =
63 getNetconfNotificationCollectorDependency().registerNotificationPublisher(new StreamBuilder()
65 .setReplaySupport(false)
66 .setDescription(getNetconfStreamDescription()).build());
68 // Notification Translator, get notification from HC producers and put into NETCONF notification collector
69 final DOMNotificationListener domNotificationListener =
71 LOG.debug("Propagating notification: {} into NETCONF", notification.getType());
72 netconfNotificationProducerReg.onNotification(streamType, notificationToXml(notification, schemaService.getGlobalContext()));
75 // NotificationManager is used to provide list of available notifications (which are all of the notifications registered)
76 // TODO make available notifications configurable here so that any number of notification streams for NETCONF
77 // can be configured on top of a single notification manager
78 LOG.debug("Current notifications to be exposed over NETCONF: {}", hcNotificationCollector.getNotificationTypes());
79 final Set<SchemaPath> currentNotificationSchemaPaths = hcNotificationCollector.getNotificationTypes()
81 .map(NotificationProducerRegistry::getQName)
82 .map(qName -> SchemaPath.create(true, qName))
83 .collect(Collectors.toSet());
85 // Register as listener to HC's DOM notification service
86 // TODO This should only be triggered when NETCONF notifications are activated
87 // Because this way we actually start all notification producers
88 // final Collection<QName> notificationQNames =
89 final ListenerRegistration<DOMNotificationListener> domNotificationListenerReg = getDomNotificationServiceDependency()
90 .registerNotificationListener(domNotificationListener, currentNotificationSchemaPaths);
92 LOG.info("Exposing NETCONF notification stream: {}", streamType.getValue());
94 domNotificationListenerReg.close();
95 netconfNotificationProducerReg.close();
100 static NetconfNotification notificationToXml(final DOMNotification domNotification, final SchemaContext ctx) {
101 LOG.trace("Transforming notification: {} into XML", domNotification.getType());
103 final SchemaPath type = domNotification.getType();
104 final QName notificationQName = type.getLastComponent();
105 final DOMResult result = prepareDomResultForRpcRequest(notificationQName);
108 writeNormalizedRpc(domNotification, result, type, ctx);
109 } catch (final XMLStreamException | IOException | IllegalStateException e) {
110 LOG.warn("Unable to transform notification: {} into XML", domNotification.getType(), e);
111 throw new IllegalArgumentException("Unable to serialize " + type, e);
114 final Document node = result.getNode().getOwnerDocument();
115 return new NetconfNotification(node);
118 private static DOMResult prepareDomResultForRpcRequest(final QName notificationQName) {
119 final Document document = XmlUtil.newDocument();
120 final Element notificationElement =
121 document.createElementNS(notificationQName.getNamespace().toString(), notificationQName.getLocalName());
122 document.appendChild(notificationElement);
123 return new DOMResult(notificationElement);
126 private static final XMLOutputFactory XML_FACTORY;
129 XML_FACTORY = XMLOutputFactory.newFactory();
130 XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
133 private static void writeNormalizedRpc(final DOMNotification normalized, final DOMResult result,
134 final SchemaPath schemaPath, final SchemaContext baseNetconfCtx)
135 throws IOException, XMLStreamException {
136 final XMLStreamWriter writer = XML_FACTORY.createXMLStreamWriter(result);
138 try (final NormalizedNodeStreamWriter normalizedNodeStreamWriter =
139 XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath)) {
140 try (final NormalizedNodeWriter normalizedNodeWriter =
141 NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter)) {
142 for (DataContainerChild<?, ?> dataContainerChild : normalized.getBody().getValue()) {
143 normalizedNodeWriter.write(dataContainerChild);
145 normalizedNodeWriter.flush();
151 } catch (final Exception e) {
152 LOG.warn("Unable to close resource properly. Ignoring", e);