public static final String SOURCE_KEY = "source";
public static final String RPC_KEY = "rpc";
public static final String NOTIFICATION_ELEMENT_NAME = "notification";
+ public static final String EVENT_TIME = "eventTime";
public static final String MESSAGE_ID = "message-id";
public static final String SESSION_ID = "session-id";
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_0 = "urn:ietf:params:netconf:base:1.0";
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_1 = "urn:ietf:params:netconf:base:1.1";
public static final String URN_IETF_PARAMS_XML_NS_NETCONF_EXI_1_0 = "urn:ietf:params:xml:ns:netconf:exi:1.0";
+ public static final String URN_IETF_PARAMS_NETCONF_CAPABILITY_NOTIFICATION_1_0 = "urn:ietf:params:netconf:capability:notification:1.0";
public static final String URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0 = "urn:ietf:params:netconf:capability:exi:1.0";
public static final String URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.impl.osgi.NetconfOperationRouter;
+import org.opendaylight.netconf.util.messages.SubtreeFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
Document rpcReply = operationRouter.onNetconfMessage(incomingDocument, session);
- rpcReply = SubtreeFilter.applySubtreeFilter(incomingDocument, rpcReply);
+ rpcReply = SubtreeFilter.applyRpcSubtreeFilter(incomingDocument, rpcReply);
session.onIncommingRpcSuccess();
*/
public static final Date UNKNOWN_EVENT_TIME = new Date(0);
+ private final Date eventTime;
+
/**
* Create new notification and capture the timestamp in the constructor
*/
*/
public NetconfNotification(final Document notificationContent, final Date eventTime) {
super(wrapNotification(notificationContent, eventTime));
+ this.eventTime = eventTime;
+ }
+
+ /**
+ * @return notification event time
+ */
+ public Date getEventTime() {
+ return eventTime;
}
private static Document wrapNotification(final Document notificationContent, final Date eventTime) {
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
+import java.util.Date;
import java.util.List;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.netconf.notifications.NotificationListenerRegistration;
import org.opendaylight.netconf.notifications.impl.NetconfNotificationManager;
import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.opendaylight.netconf.util.messages.SubtreeFilter;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
import org.slf4j.Logger;
// FIXME reimplement using CODEC_REGISTRY and parse everything into generated class instance
// Waiting ofr https://git.opendaylight.org/gerrit/#/c/13763/
- // FIXME filter could be supported same way as netconf server filters get and get-config results
final Optional<XmlElement> filter = operationElement.getOnlyChildElementWithSameNamespaceOptionally("filter");
- Preconditions.checkArgument(filter.isPresent() == false, "Filter element not yet supported");
// Replay not supported
final Optional<XmlElement> startTime = operationElement.getOnlyChildElementWithSameNamespaceOptionally("startTime");
}
final NotificationListenerRegistration notificationListenerRegistration =
- notifications.registerNotificationListener(streamNameType, new NotificationSubscription(netconfSession));
+ notifications.registerNotificationListener(streamNameType, new NotificationSubscription(netconfSession, filter));
subscriptions.add(notificationListenerRegistration);
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
private static class NotificationSubscription implements NetconfNotificationListener {
private final NetconfSession currentSession;
+ private final Optional<XmlElement> filter;
- public NotificationSubscription(final NetconfSession currentSession) {
+ public NotificationSubscription(final NetconfSession currentSession, final Optional<XmlElement> filter) {
this.currentSession = currentSession;
+ this.filter = filter;
}
@Override
public void onNotification(final StreamNameType stream, final NetconfNotification notification) {
- currentSession.sendMessage(notification);
+ if (filter.isPresent()) {
+ try {
+ final Optional<Document> filtered = SubtreeFilter.applySubtreeNotificationFilter(this.filter.get(), notification.getDocument());
+ if (filtered.isPresent()) {
+ final Date eventTime = notification.getEventTime();
+ currentSession.sendMessage(new NetconfNotification(filtered.get(), eventTime));
+ }
+ } catch (DocumentedException e) {
+ LOG.warn(e.toString());
+ currentSession.sendMessage(notification);
+ }
+ } else {
+ currentSession.sendMessage(notification);
+ }
}
}
}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.impl;
+package org.opendaylight.netconf.util.messages;
import com.google.common.base.Optional;
import java.io.IOException;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.config.util.xml.XmlUtil;
-import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
public class SubtreeFilter {
private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilter.class);
- static Document applySubtreeFilter(Document requestDocument, Document rpcReply) throws DocumentedException {
+ public static Document applyRpcSubtreeFilter(Document requestDocument, Document rpcReply) throws DocumentedException {
OperationNameAndNamespace operationNameAndNamespace = new OperationNameAndNamespace(requestDocument);
if (XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0.equals(operationNameAndNamespace.getNamespace()) &&
XmlNetconfConstants.GET.equals(operationNameAndNamespace.getOperationName()) ||
return rpcReply;
}
- // FIXME: rpcReply document must be reread otherwise some nodes do not inherit namespaces. (services/service)
- try {
- rpcReply = XmlUtil.readXmlToDocument(XmlUtil.toString(rpcReply, true));
- } catch (SAXException | IOException e) {
- LOG.error("Cannot transform document", e);
- throw new DocumentedException("Cannot transform document" + e);
- }
+ rpcReply = reReadDocument(rpcReply);
XmlElement filter = maybeFilter.get();
- if ("subtree".equals(filter.getAttribute("type"))||
- "subtree".equals(filter.getAttribute("type", XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0))) {
+ if (isSupported(filter)) {
// do
return filtered(maybeFilter.get(), rpcReply);
return rpcReply; // return identical document
}
+ /**
+ * Filters notification content. If filter type isn't of type "subtree", returns unchanged notification content.
+ * If no match is found, absent is returned.
+ * @param filter filter
+ * @param notification notification
+ * @return document containing filtered notification content
+ * @throws DocumentedException
+ */
+ public static Optional<Document> applySubtreeNotificationFilter(XmlElement filter, Document notification) throws DocumentedException {
+ notification = reReadDocument(notification);
+ removeEventTimeNode(notification);
+ if (isSupported(filter)) {
+ return Optional.fromNullable(filteredNotification(filter, notification));
+ }
+ return Optional.of(extractNotificationContent(notification));
+ }
+
+ private static Document reReadDocument(Document notification) throws DocumentedException {
+ // FIXME: rpcReply document must be reread otherwise some nodes do not inherit namespaces. (services/service)
+ try {
+ notification = XmlUtil.readXmlToDocument(XmlUtil.toString(notification, true));
+ } catch (SAXException | IOException e) {
+ LOG.error("Cannot transform document", e);
+ throw new DocumentedException("Cannot transform document" + e);
+ }
+ return notification;
+ }
+
+ private static void removeEventTimeNode(Document document) {
+ final Node eventTimeNode = document.getDocumentElement().getElementsByTagNameNS(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_NOTIFICATION_1_0, XmlNetconfConstants.EVENT_TIME).item(0);
+ document.getDocumentElement().removeChild(eventTimeNode);
+ }
+
+ private static boolean isSupported(XmlElement filter) {
+ return "subtree".equals(filter.getAttribute("type"))||
+ "subtree".equals(filter.getAttribute("type", XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
+ }
+
+ private static Document extractNotificationContent(Document notification) throws DocumentedException {
+ XmlElement root = XmlElement.fromDomElement(notification.getDocumentElement());
+ XmlElement content = root.getOnlyChildElement();
+ notification.removeChild(root.getDomElement());
+ notification.appendChild(content.getDomElement());
+ return notification;
+ }
+
+ private static Document filteredNotification(XmlElement filter, Document originalNotification) throws DocumentedException {
+ Document result = XmlUtil.newDocument();
+ XmlElement dataSrc = XmlElement.fromDomDocument(originalNotification);
+ Element dataDst = (Element) result.importNode(dataSrc.getDomElement(), false);
+ for (XmlElement filterChild : filter.getChildElements()) {
+ addSubtree2(filterChild, dataSrc.getOnlyChildElement(), XmlElement.fromDomElement(dataDst));
+ }
+ if(dataDst.getFirstChild() != null) {
+ result.appendChild(dataDst.getFirstChild());
+ return result;
+ } else {
+ return null;
+ }
+ }
+
private static Document filtered(XmlElement filter, Document originalReplyDocument) throws DocumentedException {
Document result = XmlUtil.newDocument();
// even if filter is empty, copy /rpc/data
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.util.messages;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+@RunWith(value = Parameterized.class)
+public class SubtreeFilterNotificationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterRpcTest.class);
+
+ private final int directoryIndex;
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ List<Object[]> result = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ result.add(new Object[]{i});
+ }
+ return result;
+ }
+
+ public SubtreeFilterNotificationTest(int directoryIndex) {
+ this.directoryIndex = directoryIndex;
+ }
+
+ @Before
+ public void setUp(){
+ XMLUnit.setIgnoreWhitespace(true);
+ }
+
+ @Test
+ public void testFilterNotification() throws Exception {
+ XmlElement filter = XmlElement.fromDomDocument(getDocument("filter.xml"));
+ Document preFilterDocument = getDocument("pre-filter.xml");
+ Document postFilterDocument = getDocument("post-filter.xml");
+ Optional<Document> actualPostFilterDocumentOpt = SubtreeFilter.applySubtreeNotificationFilter(filter, preFilterDocument);
+ if(actualPostFilterDocumentOpt.isPresent()) {
+ Document actualPostFilterDocument = actualPostFilterDocumentOpt.get();
+ LOG.info("Actual document: {}", XmlUtil.toString(actualPostFilterDocument));
+ Diff diff = XMLUnit.compareXML(postFilterDocument, actualPostFilterDocument);
+ assertTrue(diff.toString(), diff.similar());
+ } else {
+ assertEquals("empty", XmlElement.fromDomDocument(postFilterDocument).getName());
+ }
+ }
+
+ public Document getDocument(String fileName) throws SAXException, IOException {
+ return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/notification/" + directoryIndex + "/" +
+ fileName));
+ }
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.impl;
+package org.opendaylight.netconf.util.messages;
import static org.junit.Assert.assertTrue;
import org.xml.sax.SAXException;
@RunWith(value = Parameterized.class)
-public class SubtreeFilterTest {
- private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterTest.class);
+public class SubtreeFilterRpcTest {
+ private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterRpcTest.class);
private final int directoryIndex;
return result;
}
- public SubtreeFilterTest(int directoryIndex) {
+ public SubtreeFilterRpcTest(int directoryIndex) {
this.directoryIndex = directoryIndex;
}
Document requestDocument = getDocument("request.xml");
Document preFilterDocument = getDocument("pre-filter.xml");
Document postFilterDocument = getDocument("post-filter.xml");
- Document actualPostFilterDocument = SubtreeFilter.applySubtreeFilter(requestDocument, preFilterDocument);
+ Document actualPostFilterDocument = SubtreeFilter.applyRpcSubtreeFilter(requestDocument, preFilterDocument);
LOG.info("Actual document: {}", XmlUtil.toString(actualPostFilterDocument));
Diff diff = XMLUnit.compareXML(postFilterDocument, actualPostFilterDocument);
assertTrue(diff.toString(), diff.similar());
}
public Document getDocument(String fileName) throws SAXException, IOException {
- return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/" + directoryIndex + "/" +
+ return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/rpc/" + directoryIndex + "/" +
fileName));
}
}
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+</netconf-session-end>
+
+
+
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="unsupported">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-end>
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="unsupported">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-start>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-start>
+ <eventTime>2016-03-17T13:15:04+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<empty/>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-start>
+ <eventTime>2016-03-17T13:15:04+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"/>
+</filter>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-end>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
\ No newline at end of file