2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.test.tool.rpc;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Maps;
13 import java.io.IOException;
14 import java.text.SimpleDateFormat;
15 import java.util.Date;
16 import java.util.List;
18 import java.util.Optional;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.TimeUnit;
22 import javax.xml.bind.JAXBContext;
23 import javax.xml.bind.JAXBException;
24 import javax.xml.bind.Unmarshaller;
25 import javax.xml.bind.annotation.XmlRootElement;
26 import org.opendaylight.netconf.api.NetconfMessage;
27 import org.opendaylight.netconf.api.xml.XmlElement;
28 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
29 import org.opendaylight.netconf.api.xml.XmlUtil;
30 import org.opendaylight.netconf.server.NetconfServerSession;
31 import org.opendaylight.netconf.server.api.operations.AbstractLastNetconfOperation;
32 import org.opendaylight.netconf.server.mapping.operations.DefaultNetconfOperation;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Element;
35 import org.xml.sax.SAXException;
37 public class SimulatedCreateSubscription extends AbstractLastNetconfOperation implements DefaultNetconfOperation {
38 private final Map<Notification, NetconfMessage> notifications;
40 private NetconfServerSession session;
41 private ScheduledExecutorService scheduledExecutorService;
43 public SimulatedCreateSubscription(final String id, final Optional<File> notificationsFile) {
46 final Optional<Notifications> notifs;
48 if (notificationsFile.isPresent()) {
49 notifs = Optional.of(loadNotifications(notificationsFile.orElseThrow()));
50 scheduledExecutorService = Executors.newScheduledThreadPool(1);
52 notifs = Optional.empty();
55 if (notifs.isPresent()) {
56 final List<Notification> toCopy = notifs.orElseThrow().getNotificationList();
57 final Map<Notification, NetconfMessage> preparedMessages = Maps.newHashMapWithExpectedSize(toCopy.size());
58 for (final Notification notification : toCopy) {
59 final NetconfMessage parsedNotification = parseNetconfNotification(notification.getContent());
60 preparedMessages.put(notification, parsedNotification);
62 notifications = preparedMessages;
64 notifications = Map.of();
68 private static Notifications loadNotifications(final File file) {
70 final JAXBContext jaxbContext = JAXBContext.newInstance(Notifications.class);
71 final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
72 return (Notifications) jaxbUnmarshaller.unmarshal(file);
73 } catch (final JAXBException e) {
74 throw new IllegalArgumentException("Canot parse file " + file + " as a notifications file", e);
79 protected String getOperationName() {
80 return "create-subscription";
84 protected String getOperationNamespace() {
85 return "urn:ietf:params:xml:ns:netconf:notification:1.0";
89 protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) {
90 long delayAggregator = 0;
92 for (final Map.Entry<Notification, NetconfMessage> notification : notifications.entrySet()) {
93 for (int i = 0; i <= notification.getKey().getTimes(); i++) {
95 delayAggregator += notification.getKey().getDelayInSeconds();
97 scheduledExecutorService.schedule(() -> {
98 Preconditions.checkState(session != null, "Session is not set, cannot process notifications");
99 session.sendMessage(notification.getValue());
100 }, delayAggregator, TimeUnit.SECONDS);
103 return document.createElement(XmlNetconfConstants.OK);
106 private static NetconfMessage parseNetconfNotification(String content) {
107 final int startEventTime = content.indexOf("<eventTime>") + "<eventTime>".length();
108 final int endEventTime = content.indexOf("</eventTime>");
109 final String eventTime = content.substring(startEventTime, endEventTime);
110 if (eventTime.equals("XXXX")) {
111 content = content.replace(eventTime, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
115 return new NetconfMessage(XmlUtil.readXmlToDocument(content));
116 } catch (SAXException | IOException e) {
117 throw new IllegalArgumentException("Cannot parse notifications", e);
122 public void setNetconfSession(final NetconfServerSession newSession) {
123 session = newSession;
126 @XmlRootElement(name = "notifications")
127 public static final class Notifications {
129 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "notification", required = true)
130 private List<Notification> notificationList;
132 public List<Notification> getNotificationList() {
133 return notificationList;
137 public String toString() {
138 final StringBuilder sb = new StringBuilder("Notifications{");
139 sb.append("notificationList=").append(notificationList);
141 return sb.toString();
145 public static final class Notification {
147 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "delay")
148 private long delayInSeconds;
150 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "times")
153 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "content", required = true)
154 private String content;
156 public long getDelayInSeconds() {
157 return delayInSeconds;
160 public long getTimes() {
164 public String getContent() {
169 public String toString() {
170 final StringBuilder sb = new StringBuilder("Notification{");
171 sb.append("delayInSeconds=").append(delayInSeconds);
172 sb.append(", times=").append(times);
173 sb.append(", content='").append(content).append('\'');
175 return sb.toString();