1c4cb98b483c720f71efc8b2df27c5b40e6505e7
[ccsdk/features.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : CCSDK
4  * ================================================================================
5  * Copyright (C) 2021-2022 Wipro Limited.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.ccsdk.features.sdnr.northbound.addCMHandle;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.google.common.util.concurrent.ListenableFuture;
26
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 import java.sql.Timestamp;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Properties;
37
38 import org.eclipse.jdt.annotation.NonNull;
39 import org.onap.ccsdk.features.sdnr.northbound.addCMHandle.HttpRequester;
40 import org.onap.ccsdk.features.sdnr.northbound.addCMHandle.models.CpsCmHandleRequestBody;
41 import org.onap.ccsdk.sli.core.utils.common.EnvProperties;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.api.DataObjectModification;
44 import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
45 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
46 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
47 import org.opendaylight.mdsal.binding.api.DataTreeModification;
48 import org.opendaylight.mdsal.binding.api.MountPointService;
49 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
50 import org.opendaylight.mdsal.binding.api.RpcProviderService;
51 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
52 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
53 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
54 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
55 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev210615.AddCMHandleInput;
56 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev210615.AddCMHandleOutput;
57 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev210615.AddCMHandleOutputBuilder;
58 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev210615.CMHandleAPIService;
59 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev210615.status.StatusBuilder;
60 import org.opendaylight.yang.gen.v1.org.onap.cps.ncmp.rev210520.DmiRegistryBuilder;
61 import org.opendaylight.yang.gen.v1.org.onap.cps.ncmp.rev210520.dmi.registry.CmHandle;
62 import org.opendaylight.yang.gen.v1.org.onap.cps.ncmp.rev210520.dmi.registry.CmHandleBuilder;
63 import org.opendaylight.yang.gen.v1.org.onap.cps.ncmp.rev210520.dmi.registry.CmHandleKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
71 import org.opendaylight.yangtools.concepts.ListenerRegistration;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.common.RpcResult;
74 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
75 import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 public class AddCMHandleProvider implements CMHandleAPIService, AutoCloseable {
80
81     private static final Logger LOG = LoggerFactory.getLogger(AddCMHandleProvider.class);
82     private final ObjectMapper objMapper = new ObjectMapper();
83     private final String APPLICATION_NAME = "addCMHandle";
84     private static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR";
85     private static final String PROPERTIES_FILE_NAME = "cm-handle.properties";
86     private static HashMap<String, String> config;
87     private ListenerRegistration<AddCmHandleListener> listener;
88     private static final @NonNull InstanceIdentifier<Node> NETCONF_NODE_TOPO_IID =
89             InstanceIdentifier.create(NetworkTopology.class)
90                     .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
91                     .child(Node.class);
92     private static final @NonNull DataTreeIdentifier<Node> NETCONF_NODE_TOPO_TREE_ID =
93             DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
94
95     private DataBroker dataBroker;
96     private MountPointService mountPointService;
97     private DOMMountPointService domMountPointService;
98     private RpcProviderService rpcProviderRegistry;
99     @SuppressWarnings("unused")
100     private NotificationPublishService notificationPublishService;
101     @SuppressWarnings("unused")
102     private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
103     private YangParserFactory yangParserFactory;
104     private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
105     private Boolean isInitializationSuccessful = false;
106     private Long lastNotificationSentOn = Long.valueOf(0);
107     private List<String> nodeIdList = new ArrayList<>();
108
109     public AddCMHandleProvider() {
110
111         LOG.info("Creating provider for {}", APPLICATION_NAME);
112         this.dataBroker = null;
113         this.mountPointService = null;
114         this.domMountPointService = null;
115         this.rpcProviderRegistry = null;
116         this.notificationPublishService = null;
117         this.clusterSingletonServiceProvider = null;
118         this.yangParserFactory = null;
119         this.bindingNormalizedNodeSerializer = null;
120
121     }
122
123     public void setDataBroker(DataBroker dataBroker) {
124         this.dataBroker = dataBroker;
125     }
126
127     public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) {
128         this.rpcProviderRegistry = rpcProviderRegistry;
129     }
130
131     public void setNotificationPublishService(NotificationPublishService notificationPublishService) {
132         this.notificationPublishService = notificationPublishService;
133     }
134
135     public void setMountPointService(MountPointService mountPointService) {
136         this.mountPointService = mountPointService;
137     }
138
139     public void setDomMountPointService(DOMMountPointService domMountPointService) {
140         this.domMountPointService = domMountPointService;
141     }
142
143     public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) {
144         this.clusterSingletonServiceProvider = clusterSingletonService;
145     }
146
147     public void setYangParserFactory(YangParserFactory yangParserFactory) {
148         this.yangParserFactory = yangParserFactory;
149     }
150
151     public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
152         this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
153         LOG.info("Init bindingNormalizedNodeSerializer");
154     }
155
156     public Boolean isInitializationSuccessful() {
157         return isInitializationSuccessful;
158     }
159
160     public void init() {
161         LOG.info("Initializing {} for {}", this.getClass().getName(), APPLICATION_NAME);
162
163         String propDir = System.getenv(SDNC_CONFIG_DIR);
164         if (propDir == null) {
165             LOG.error("Environment variable SDNC_CONFIG_DIR is not set");
166             propDir = "/opt/onap/ccsdk/data/properties/";
167         } else if (!propDir.endsWith("/")) {
168             propDir = propDir + "/";
169         }
170
171         config = new HashMap<String, String>();
172
173         try (FileInputStream fileInput = new FileInputStream(propDir + PROPERTIES_FILE_NAME)) {
174             EnvProperties properties = new EnvProperties();
175             properties.load(fileInput);
176
177             for (String param : new String[] {"cpsUrl", "user", "password", "dmaapUrl", "dmiServiceName", "client",
178                     "timerThreshold"}) {
179                 config.put(param, properties.getProperty(param));
180             }
181         } catch (IOException e) {
182             LOG.error("Error while reading properties file: ", e);
183         }
184
185         listener = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new AddCmHandleListener());
186         isInitializationSuccessful = true;
187         LOG.info("Initialization complete for {}", APPLICATION_NAME);
188         LOG.info("addCMHandle Session Initiated");
189     }
190
191     /**
192      * AddCmHandleListener
193      */
194     private class AddCmHandleListener implements DataTreeChangeListener<Node> {
195
196         @Override
197         public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
198             LOG.info("AddCmHandleListener TreeChange enter changes: {}", changes.size());
199             LOG.info("config: " + config);
200             String nodeId = getNodeId(changes);
201             if (Objects.nonNull(nodeId) && !(nodeIdList.contains(nodeId))) {
202                 nodeIdList.add(nodeId);
203             }
204             Timestamp currentTime = new Timestamp(System.currentTimeMillis());
205             Long difference = currentTime.getTime() - lastNotificationSentOn;
206             if (difference > Long.valueOf(config.get("timerThreshold"))) {
207                 sendNotification(nodeIdList);
208                 nodeIdList.clear();
209             }
210
211         }
212     }
213
214     /**
215      * Method to get nodeId.
216      */
217     private String getNodeId(@NonNull Collection<DataTreeModification<Node>> changes) {
218         String nodeIdString = null;
219         for (final DataTreeModification<Node> change : changes) {
220
221             final DataObjectModification<Node> root = change.getRootNode();
222             try {
223                 ModificationType modificationTyp = root.getModificationType();
224                 if ((modificationTyp != ModificationType.DELETE)) {
225
226                     Node node = root.getDataAfter();
227                     NodeId nodeId = node != null ? node.getNodeId() : null;
228                     if (nodeId == null) {
229                         LOG.info("without nodeid");
230                     } else {
231                         nodeIdString = nodeId.getValue();
232                         LOG.info("AddCmHandle for nodeId: {}", nodeIdString);
233                     }
234                 }
235
236             } catch (NullPointerException | IllegalStateException e) {
237                 LOG.info("Data not available at ", e);
238             }
239         }
240
241         return nodeIdString;
242     }
243
244     /**
245      * Method called when cm-handle notification is to be sent.
246      */
247     protected void sendNotification(List<String> nodeIdList) {
248
249         String sendNotificationTo = config.get("client");
250         lastNotificationSentOn = new Timestamp(System.currentTimeMillis()).getTime();
251         if (sendNotificationTo.equalsIgnoreCase("CPS")) {
252             sendNotificationToCps(nodeIdList);
253
254         }
255         if (sendNotificationTo.equalsIgnoreCase("DMAAP")) {
256             sendNotificationToDmaap(nodeIdList);
257         }
258
259         else {
260             sendNotificationToCps(nodeIdList);
261             sendNotificationToDmaap(nodeIdList);
262         }
263         lastNotificationSentOn = new Timestamp(System.currentTimeMillis()).getTime();
264
265     }
266
267     /**
268      * Method called when cm-handle notification is to be sent to CPS.
269      */
270     protected String sendNotificationToCps(List<String> nodeIdList) {
271
272         LOG.info("Sending Notification to CPS");
273         String userCredential = config.get("user") + ":" + config.get("password");
274         String url = config.get("cpsUrl");
275         String requestBody = null;
276         CpsCmHandleRequestBody cpsCmHandleRequestBody = new CpsCmHandleRequestBody(nodeIdList);
277         LOG.info("url {}", url);
278         LOG.info("userCredential: {}", userCredential);
279         try {
280             requestBody = objMapper.writeValueAsString(cpsCmHandleRequestBody);
281             LOG.info("requestBody{} ", requestBody);
282         } catch (JsonProcessingException e) {
283             LOG.error("ERROR: {}", e);
284         }
285         String response = HttpRequester.sendPostRequest(url, userCredential, requestBody);
286         LOG.info("response from CPS: {} ", response);
287         return response;
288
289     }
290
291     /**
292      * Method called when cm-handle notification is to be sent to Dmaap.
293      */
294     protected String sendNotificationToDmaap(List<String> nodeIdList) {
295
296         LOG.info("Sending Notification to Dmaap");
297         String url = config.get("dmaapUrl");
298         Map<CmHandleKey, CmHandle> values = new HashMap<>();
299         nodeIdList.forEach(nodeId -> {
300             CmHandleBuilder cmHandleBuilder = new CmHandleBuilder();
301             cmHandleBuilder.setDmiServiceName(config.get("dmiServiceName"));
302             cmHandleBuilder.setId(nodeId);
303             CmHandleKey cmHandleKey = new CmHandleKey(nodeId);
304             values.put(cmHandleKey, cmHandleBuilder.build());
305         });
306         DmiRegistryBuilder dmiRegistryBuilder = new DmiRegistryBuilder();
307         dmiRegistryBuilder.setCmHandle(values);
308
309         String requestBody = null;
310         LOG.info("url: {}", url);
311         try {
312             requestBody = objMapper.writeValueAsString(dmiRegistryBuilder.build());
313             LOG.info("requestBody: {}", requestBody);
314         } catch (JsonProcessingException e) {
315             LOG.error("ERROR: {}", e);
316         }
317         String response = HttpRequester.sendPostRequest(url, null, requestBody);
318         LOG.info("response from Dmaap: {}", response);
319         return response;
320
321     }
322
323     /**
324      * Method called when the blueprint container is destroyed.
325      */
326     @Override
327     public void close() {
328         if (Objects.nonNull(listener)) {
329             listener.close();
330         }
331         LOG.debug("AddCMHandleProvider Closed");
332     }
333
334     @Override
335     public ListenableFuture<RpcResult<AddCMHandleOutput>> addCMHandle(AddCMHandleInput input) {
336         StatusBuilder statusBuilder = new StatusBuilder();
337         statusBuilder.setMessage("SUCCESS");
338         return RpcResultBuilder.success(new AddCMHandleOutputBuilder().setStatus(statusBuilder.build()).build())
339                 .buildFuture();
340
341     }
342 }