2 * ============LICENSE_START========================================================================
3 * ONAP : tr-069-adapter
4 * =================================================================================================
5 * Copyright (C) 2020 CommScope Inc Intellectual Property.
6 * =================================================================================================
7 * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
9 * may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
14 * either express or implied. See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ===============LICENSE_END=======================================================================
19 package org.commscope.tr069adapter.netconf.rpc;
21 import com.google.common.base.Preconditions;
22 import com.google.common.collect.Maps;
25 import java.io.IOException;
26 import java.text.SimpleDateFormat;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Date;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.Optional;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.ScheduledExecutorService;
36 import java.util.concurrent.TimeUnit;
38 import javax.xml.bind.JAXBContext;
39 import javax.xml.bind.JAXBException;
40 import javax.xml.bind.Unmarshaller;
41 import javax.xml.bind.annotation.XmlRootElement;
42 import org.commscope.tr069adapter.netconf.error.NetconfNotificationException;
43 import org.opendaylight.netconf.api.NetconfMessage;
44 import org.opendaylight.netconf.api.xml.XmlElement;
45 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
46 import org.opendaylight.netconf.api.xml.XmlUtil;
47 import org.opendaylight.netconf.impl.NetconfServerSession;
48 import org.opendaylight.netconf.impl.mapping.operations.DefaultNetconfOperation;
49 import org.opendaylight.netconf.util.mapping.AbstractLastNetconfOperation;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54 import org.xml.sax.SAXException;
56 public class CreateSubscription extends AbstractLastNetconfOperation
57 implements DefaultNetconfOperation {
59 private static final Logger logger = LoggerFactory.getLogger(CreateSubscription.class);
60 private final Map<Notification, NetconfMessage> notifications;
61 private NetconfServerSession session;
62 private ScheduledExecutorService scheduledExecutorService;
63 private static Map<String, NetconfServerSession> netconfServerSessionMap = new HashMap<>();
64 private String deviceID;
65 private String swVersion;
66 private String hwVersion;
68 public CreateSubscription(final String id, final Optional<File> notificationsFile,
69 String deviceID, String swVersion, String hwVersion) {
73 logger.debug("CreateSubscription RPC is created with macID {}", deviceID);
74 this.deviceID = deviceID;
75 this.swVersion = swVersion;
76 this.hwVersion = hwVersion;
78 final Optional<Notifications> notifs;
80 if (notificationsFile.isPresent()) {
81 notifs = Optional.of(loadNotifications(notificationsFile.get()));
82 scheduledExecutorService = Executors.newScheduledThreadPool(1);
84 notifs = Optional.empty();
87 if (notifs.isPresent()) {
88 final Collection<Notification> toCopy = notifs.get().getNotificationList();
89 final Map<Notification, NetconfMessage> preparedMessages =
90 Maps.newHashMapWithExpectedSize(toCopy.size());
91 for (final Notification notification : toCopy) {
92 final NetconfMessage parsedNotification =
93 parseNetconfNotification(notification.getContent());
94 preparedMessages.put(notification, parsedNotification);
96 this.notifications = preparedMessages;
98 this.notifications = Collections.emptyMap();
102 private static Notifications loadNotifications(final File file) {
104 final JAXBContext jaxbContext = JAXBContext.newInstance(Notifications.class);
105 final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
106 return (Notifications) jaxbUnmarshaller.unmarshal(file);
107 } catch (final JAXBException e) {
108 throw new IllegalArgumentException("can not parse file " + file + " as a notifications file",
114 protected String getOperationName() {
115 return "create-subscription";
119 protected String getOperationNamespace() {
120 return "urn:ietf:params:xml:ns:netconf:notification:1.0";
124 protected Element handleWithNoSubsequentOperations(final Document document,
125 final XmlElement operationElement) {
126 long delayAggregator = 0;
127 for (final Map.Entry<Notification, NetconfMessage> notification : notifications.entrySet()) {
128 for (int i = 0; i <= notification.getKey().getTimes(); i++) {
130 delayAggregator += notification.getKey().getDelayInSeconds();
132 scheduledExecutorService.schedule(() -> {
133 Preconditions.checkState(session != null,
134 "Session is not set, cannot process notifications");
135 session.sendMessage(notification.getValue());
136 }, delayAggregator, TimeUnit.SECONDS);
139 return document.createElement(XmlNetconfConstants.OK);
142 private static NetconfMessage parseNetconfNotification(String content) {
143 final int startEventTime = content.indexOf("<eventTime>") + "<eventTime>".length();
144 final int endEventTime = content.indexOf("</eventTime>");
145 final String eventTime = content.substring(startEventTime, endEventTime);
146 if (eventTime.equals("XXXX")) {
147 content = content.replace(eventTime,
148 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
152 return new NetconfMessage(XmlUtil.readXmlToDocument(content));
153 } catch (SAXException | IOException e) {
154 throw new IllegalArgumentException("Cannot parse notifications", e);
159 public void setNetconfSession(final NetconfServerSession newSession) {
160 logger.debug("Adding netconf session to notification server sessions map : {}", newSession);
161 logger.debug("This CreateSubscription is setup to support macID= {}", deviceID);
162 this.session = newSession;
163 netconfServerSessionMap.put(deviceID, newSession);
166 public static void sendNotification(NetconfMessage netconfMessage, String deviceID)
167 throws NetconfNotificationException {
168 logger.debug("Request to send notification. NetConfMessage : {}", netconfMessage);
169 NetconfServerSession session = netconfServerSessionMap.get(deviceID);
170 if (session != null && session.isUp()) {
172 session.sendMessage(netconfMessage);
173 logger.debug("Successfully send notification for deviceID: {}", deviceID);
174 } catch (Exception e) {
175 logger.error("Failed to send notification. while posting got error. {}", e.toString());
176 throw new NetconfNotificationException("Exception while posting the netconf message", e);
181 "Failed to send notification. None of valid netconf session is available for {}.",
183 logger.debug("Available netconf sessions : {}", netconfServerSessionMap);
184 throw new NetconfNotificationException("NetConf active session deosn't not exist");
188 @XmlRootElement(name = "notifications")
189 public static final class Notifications {
191 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "notification", required = true)
192 private List<Notification> notificationList;
194 public List<Notification> getNotificationList() {
195 return notificationList;
199 public String toString() {
200 final StringBuilder sb = new StringBuilder("Notifications{");
201 sb.append("notificationList=").append(notificationList);
203 return sb.toString();
207 public static final class Notification {
209 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "delay")
210 private long delayInSeconds;
212 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "times")
215 @javax.xml.bind.annotation.XmlElement(nillable = false, name = "content", required = true)
216 private String content;
218 public long getDelayInSeconds() {
219 return delayInSeconds;
222 public long getTimes() {
226 public String getContent() {
231 public String toString() {
232 final StringBuilder sb = new StringBuilder("Notification{");
233 sb.append("delayInSeconds=").append(delayInSeconds);
234 sb.append(", times=").append(times);
235 sb.append(", content='").append(content).append('\'');
237 return sb.toString();