Bug-2674 Notification support for netconf testtool 58/15058/2
authorMaros Marsalek <mmarsale@cisco.com>
Mon, 9 Feb 2015 10:40:57 +0000 (11:40 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Fri, 13 Feb 2015 08:19:43 +0000 (08:19 +0000)
Change-Id: Ib301e2cccf85d4eae75629ddf681d9157b0cb585
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/DataList.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java with 93% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCommit.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java with 85% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedEditConfig.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java with 91% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedGet.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java with 87% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedGetConfig.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java with 87% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedLock.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedLock.java with 85% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedUnLock.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedUnLock.java with 85% similarity]

index e52fce7ae03372cb676b7ed6b9fe813682ef34c3..e4cc80fa749a8c6d8e20a9f54a39507049c98998 100644 (file)
@@ -78,6 +78,9 @@ public final class Main {
         @Arg(dest = "debug")
         public boolean debug;
 
+        @Arg(dest = "notification-file")
+        public File notificationFile;
+
         static ArgumentParser getParser() {
             final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
 
@@ -95,6 +98,11 @@ public final class Main {
                     .help("Directory containing yang schemas to describe simulated devices. Some schemas e.g. netconf monitoring and inet types are included by default")
                     .dest("schemas-dir");
 
+            parser.addArgument("--notification-file")
+                    .type(File.class)
+                    .help("Xml file containing notifications that should be sent to clients after create subscription is called")
+                    .dest("notification-file");
+
             parser.addArgument("--starting-port")
                     .type(Integer.class)
                     .setDefault(17830)
index a5f49474742748f3bd3556a9689e9031f270d25f..0d7ee3b9456f15e2c26c78eec5118af8edf6aeb8 100644 (file)
@@ -26,6 +26,7 @@ import io.netty.channel.local.LocalAddress;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -71,6 +72,14 @@ import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOper
 import org.opendaylight.controller.netconf.ssh.SshProxyServer;
 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfiguration;
 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder;
+import org.opendaylight.controller.netconf.test.tool.rpc.DataList;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedCommit;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedCreateSubscription;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedEditConfig;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedGet;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedGetConfig;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedLock;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedUnLock;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
@@ -116,7 +125,7 @@ public class NetconfDeviceSimulator implements Closeable {
         this.nioExecutor = nioExecutor;
     }
 
-    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout) {
+    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout, final Optional<File> notificationsFile) {
 
         final Set<Capability> capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function<ModuleBuilder, Capability>() {
             @Override
@@ -132,7 +141,7 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final SessionIdProvider idProvider = new SessionIdProvider();
 
-        final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities);
+        final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities, notificationsFile);
         final NetconfMonitoringOperationService monitoringService = new NetconfMonitoringOperationService(new NetconfMonitoringServiceImpl(simulatedOperationProvider));
         simulatedOperationProvider.addService(monitoringService);
 
@@ -183,7 +192,7 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
 
-        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout);
+        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout, Optional.fromNullable(params.notificationFile));
 
         int currentPort = params.startingPort;
 
@@ -392,9 +401,9 @@ public class NetconfDeviceSimulator implements Closeable {
         private final Set<NetconfOperationService> netconfOperationServices;
 
 
-        public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set<Capability> caps) {
+        public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set<Capability> caps, final Optional<File> notificationsFile) {
             this.idProvider = idProvider;
-            final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId());
+            final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId(), notificationsFile);
             this.netconfOperationServices = Sets.<NetconfOperationService>newHashSet(simulatedOperationService);
         }
 
@@ -433,10 +442,12 @@ public class NetconfDeviceSimulator implements Closeable {
         static class SimulatedOperationService implements NetconfOperationService {
             private final Set<Capability> capabilities;
             private final long currentSessionId;
+            private final Optional<File> notificationsFile;
 
-            public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId) {
+            public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId, final Optional<File> notificationsFile) {
                 this.capabilities = capabilities;
                 this.currentSessionId = currentSessionId;
+                this.notificationsFile = notificationsFile;
             }
 
             @Override
@@ -453,7 +464,8 @@ public class NetconfDeviceSimulator implements Closeable {
                 final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId));
                 final SimulatedLock sLock = new SimulatedLock(String.valueOf(currentSessionId));
                 final SimulatedUnLock sUnlock = new SimulatedUnLock(String.valueOf(currentSessionId));
-                return Sets.<NetconfOperation>newHashSet(sGet,  sGetConfig, sEditConfig, sCommit, sLock, sUnlock);
+                final SimulatedCreateSubscription sCreateSubs = new SimulatedCreateSubscription(String.valueOf(currentSessionId), notificationsFile);
+                return Sets.<NetconfOperation>newHashSet(sGet,  sGetConfig, sEditConfig, sCommit, sLock, sUnlock, sCreateSubs);
             }
 
             @Override
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedCommit extends AbstractConfigNetconfOperation {
+public class SimulatedCommit extends AbstractConfigNetconfOperation {
 
-    SimulatedCommit(final String netconfSessionIdForReporting) {
+    public SimulatedCommit(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }
 
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java
new file mode 100644 (file)
index 0000000..abf51c4
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 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.controller.netconf.test.tool.rpc;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+public class SimulatedCreateSubscription extends AbstractLastNetconfOperation implements DefaultNetconfOperation {
+
+    private NetconfServerSession session;
+    private final Optional<Notifications> notifications;
+    private ScheduledExecutorService scheduledExecutorService;
+
+    public SimulatedCreateSubscription(final String id, final Optional<File> notificationsFile) {
+        super(id);
+        if(notificationsFile.isPresent()) {
+            notifications = Optional.of(loadNotifications(notificationsFile.get()));
+            scheduledExecutorService = Executors.newScheduledThreadPool(1);
+        } else {
+            notifications = Optional.absent();
+        }
+    }
+
+    private Notifications loadNotifications(final File file) {
+        try {
+            final JAXBContext jaxbContext = JAXBContext.newInstance(Notifications.class);
+            final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+            return (Notifications) jaxbUnmarshaller.unmarshal(file);
+        } catch (final JAXBException e) {
+            throw new IllegalArgumentException("Canot parse file " + file + " as a notifications file", e);
+        }
+    }
+
+    @Override
+    protected String getOperationName() {
+        return "create-subscription";
+    }
+
+    @Override
+    protected String getOperationNamespace() {
+        return "urn:ietf:params:xml:ns:netconf:notification:1.0";
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+
+
+        if(notifications.isPresent()) {
+            long delayAggregator = 0;
+            System.console().writer().println("Scheduling notifications " + notifications.get());
+
+            for (final Notification notification : notifications.get().getNotificationList()) {
+                for (int i = 0; i <= notification.getTimes(); i++) {
+
+                    delayAggregator += notification.getDelayInSeconds();
+
+                    System.console().writer().println("Times " + notification.getTimes());
+                    scheduledExecutorService.schedule(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                System.console().writer().println("Sending actual notification " + notification);
+                                Preconditions.checkState(session != null, "Session is not set, cannot process notifications");
+                                session.sendMessage(parseNetconfNotification(notification.getContent()));
+                            } catch (IOException | SAXException e) {
+                                throw new IllegalStateException("Unable to process notification " + notification, e);
+                            }
+                        }
+                    }, delayAggregator, TimeUnit.SECONDS);
+                }
+            }
+        }
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    private static NetconfMessage parseNetconfNotification(String content) throws IOException, SAXException {
+        final int startEventTime = content.indexOf("<eventTime>") + "<eventTime>".length();
+        final int endEventTime = content.indexOf("</eventTime>");
+        final String eventTime = content.substring(startEventTime, endEventTime);
+        if(eventTime.equals("XXXX")) {
+            content = content.replace(eventTime, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
+        }
+
+        return new NetconfMessage(XmlUtil.readXmlToDocument(content));
+    }
+
+    @Override
+    public void setNetconfSession(final NetconfServerSession s) {
+        this.session = s;
+    }
+
+    @XmlRootElement(name = "notifications")
+    public static final class Notifications {
+
+        @javax.xml.bind.annotation.XmlElement(nillable =  false, name = "notification", required = true)
+        private List<Notification> notificationList;
+
+        public List<Notification> getNotificationList() {
+            return notificationList;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("Notifications{");
+            sb.append("notificationList=").append(notificationList);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    public static final class Notification {
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "delay")
+        private long delayInSeconds;
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "times")
+        private long times;
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "content", required = true)
+        private String content;
+
+        public long getDelayInSeconds() {
+            return delayInSeconds;
+        }
+
+        public long getTimes() {
+            return times;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("Notification{");
+            sb.append("delayInSeconds=").append(delayInSeconds);
+            sb.append(", times=").append(times);
+            sb.append(", content='").append(content).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+}
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -19,13 +19,13 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedEditConfig extends AbstractConfigNetconfOperation {
+public class SimulatedEditConfig extends AbstractConfigNetconfOperation {
     private static final String DELETE_EDIT_CONFIG = "delete";
     private static final String OPERATION = "operation";
     private static final String REMOVE_EDIT_CONFIG = "remove";
     private final DataList storage;
 
-    SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,11 +17,11 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedGet extends AbstractConfigNetconfOperation {
+public class SimulatedGet extends AbstractConfigNetconfOperation {
 
     private final DataList storage;
 
-    SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,11 +17,11 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedGetConfig extends AbstractConfigNetconfOperation {
+public class SimulatedGetConfig extends AbstractConfigNetconfOperation {
 
     private final DataList storage;
 
-    SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedLock extends AbstractConfigNetconfOperation {
+public class SimulatedLock extends AbstractConfigNetconfOperation {
 
-    SimulatedLock(final String netconfSessionIdForReporting) {
+    public SimulatedLock(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }
 
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedUnLock extends AbstractConfigNetconfOperation {
+public class SimulatedUnLock extends AbstractConfigNetconfOperation {
 
-    SimulatedUnLock(final String netconfSessionIdForReporting) {
+    public SimulatedUnLock(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }