Migrate netconf-console to Karaf 4 way
[netconf.git] / netconf / tools / netconf-testtool / src / main / java / org / opendaylight / netconf / test / tool / rpc / SimulatedCreateSubscription.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.test.tool.rpc;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Maps;
13 import java.io.File;
14 import java.io.IOException;
15 import java.text.SimpleDateFormat;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Date;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.TimeUnit;
24 import javax.xml.bind.JAXBContext;
25 import javax.xml.bind.JAXBException;
26 import javax.xml.bind.Unmarshaller;
27 import javax.xml.bind.annotation.XmlRootElement;
28 import org.opendaylight.netconf.api.NetconfMessage;
29 import org.opendaylight.netconf.api.xml.XmlElement;
30 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
31 import org.opendaylight.netconf.api.xml.XmlUtil;
32 import org.opendaylight.netconf.impl.NetconfServerSession;
33 import org.opendaylight.netconf.impl.mapping.operations.DefaultNetconfOperation;
34 import org.opendaylight.netconf.util.mapping.AbstractLastNetconfOperation;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.xml.sax.SAXException;
38
39 public class SimulatedCreateSubscription extends AbstractLastNetconfOperation implements DefaultNetconfOperation {
40
41     private final Map<Notification, NetconfMessage> notifications;
42     private NetconfServerSession session;
43     private ScheduledExecutorService scheduledExecutorService;
44
45     public SimulatedCreateSubscription(final String id, final Optional<File> notificationsFile) {
46         super(id);
47
48         final Optional<Notifications> notifs;
49
50         if (notificationsFile.isPresent()) {
51             notifs = Optional.of(loadNotifications(notificationsFile.get()));
52             scheduledExecutorService = Executors.newScheduledThreadPool(1);
53         } else {
54             notifs = Optional.absent();
55         }
56
57         if (notifs.isPresent()) {
58             final Collection<Notification> toCopy = notifs.get().getNotificationList();
59             final Map<Notification, NetconfMessage> preparedMessages = Maps.newHashMapWithExpectedSize(toCopy.size());
60             for (final Notification notification : toCopy) {
61                 final NetconfMessage parsedNotification = parseNetconfNotification(notification.getContent());
62                 preparedMessages.put(notification, parsedNotification);
63             }
64             this.notifications = preparedMessages;
65         } else {
66             this.notifications = Collections.emptyMap();
67         }
68     }
69
70     private static Notifications loadNotifications(final File file) {
71         try {
72             final JAXBContext jaxbContext = JAXBContext.newInstance(Notifications.class);
73             final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
74             return (Notifications) jaxbUnmarshaller.unmarshal(file);
75         } catch (final JAXBException e) {
76             throw new IllegalArgumentException("Canot parse file " + file + " as a notifications file", e);
77         }
78     }
79
80     @Override
81     protected String getOperationName() {
82         return "create-subscription";
83     }
84
85     @Override
86     protected String getOperationNamespace() {
87         return "urn:ietf:params:xml:ns:netconf:notification:1.0";
88     }
89
90     @Override
91     protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) {
92         long delayAggregator = 0;
93
94         for (final Map.Entry<Notification, NetconfMessage> notification : notifications.entrySet()) {
95             for (int i = 0; i <= notification.getKey().getTimes(); i++) {
96
97                 delayAggregator += notification.getKey().getDelayInSeconds();
98
99                 scheduledExecutorService.schedule(() -> {
100                     Preconditions.checkState(session != null, "Session is not set, cannot process notifications");
101                     session.sendMessage(notification.getValue());
102                 }, delayAggregator, TimeUnit.SECONDS);
103             }
104         }
105         return XmlUtil.createElement(document, XmlNetconfConstants.OK);
106     }
107
108     private static NetconfMessage parseNetconfNotification(String content) {
109         final int startEventTime = content.indexOf("<eventTime>") + "<eventTime>".length();
110         final int endEventTime = content.indexOf("</eventTime>");
111         final String eventTime = content.substring(startEventTime, endEventTime);
112         if (eventTime.equals("XXXX")) {
113             content = content.replace(eventTime, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
114         }
115
116         try {
117             return new NetconfMessage(XmlUtil.readXmlToDocument(content));
118         } catch (SAXException | IOException e) {
119             throw new IllegalArgumentException("Cannot parse notifications", e);
120         }
121     }
122
123     @Override
124     public void setNetconfSession(final NetconfServerSession newSession) {
125         this.session = newSession;
126     }
127
128     @XmlRootElement(name = "notifications")
129     public static final class Notifications {
130
131         @javax.xml.bind.annotation.XmlElement(nillable =  false, name = "notification", required = true)
132         private List<Notification> notificationList;
133
134         public List<Notification> getNotificationList() {
135             return notificationList;
136         }
137
138         @Override
139         public String toString() {
140             final StringBuilder sb = new StringBuilder("Notifications{");
141             sb.append("notificationList=").append(notificationList);
142             sb.append('}');
143             return sb.toString();
144         }
145     }
146
147     public static final class Notification {
148
149         @javax.xml.bind.annotation.XmlElement(nillable = false, name = "delay")
150         private long delayInSeconds;
151
152         @javax.xml.bind.annotation.XmlElement(nillable = false, name = "times")
153         private long times;
154
155         @javax.xml.bind.annotation.XmlElement(nillable = false, name = "content", required = true)
156         private String content;
157
158         public long getDelayInSeconds() {
159             return delayInSeconds;
160         }
161
162         public long getTimes() {
163             return times;
164         }
165
166         public String getContent() {
167             return content;
168         }
169
170         @Override
171         public String toString() {
172             final StringBuilder sb = new StringBuilder("Notification{");
173             sb.append("delayInSeconds=").append(delayInSeconds);
174             sb.append(", times=").append(times);
175             sb.append(", content='").append(content).append('\'');
176             sb.append('}');
177             return sb.toString();
178         }
179     }
180 }