2e6ae742b38a6e0029cfb50a64f718022edf5b08
[ccsdk/sli/northbound.git] / dmaap-listener / src / main / java / org / onap / ccsdk / sli / northbound / dmaapclient / OofPciPocDmaapConsumers.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *             reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.northbound.dmaapclient;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileReader;
27 import java.io.IOException;
28 import java.io.StringWriter;
29 import java.io.Writer;
30 import java.time.Instant;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Properties;
34 import org.apache.velocity.VelocityContext;
35 import org.apache.velocity.app.VelocityEngine;
36 import org.json.JSONArray;
37 import org.json.JSONObject;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import com.fasterxml.jackson.databind.JsonNode;
41 import com.fasterxml.jackson.databind.ObjectMapper;
42
43 public class OofPciPocDmaapConsumers extends SdncDmaapConsumerImpl {
44
45     private static final Logger LOG = LoggerFactory.getLogger(OofPciPocDmaapConsumers.class);
46     private static final String SDNC_ENDPOINT = "SDNC.endpoint";
47     private static final String TEMPLATE = "SDNC.template";
48     private static final String DMAAPLISTENERROOT = "DMAAPLISTENERROOT";
49     private static final String UTF_8 = "UTF-8";
50
51     private static final String PARAMETER_NAME = "parameter-name";
52     private static final String STRING_VALUE = "string-value";
53     private static final String PHYSICAL_CELL_ID_INPUT_FAP_SERVICE = "configuration-phy-cell-id-input.fap-service";
54     private static final String EVENT_HEADER = "event-header";
55         private static final String ACTION = "Action";
56         private static final String CONFIGURATIONS = "Configurations";
57         private static final String MODIFY_CONFIG = "ModifyConfig";
58         private static final String DATA = "data";
59         private static final String FAP_SERVICE = "FAPService";
60         
61         private static final String PAYLOAD = "Payload";
62         private static final String PCI_CHANGES_MAP_FILE_NAME = "pci-changes-from-policy-to-sdnr";
63         private static final String SLI_PARAMETERS = "sli_parameters";
64         private static final String RPC_NAME = "rpc-name";
65         private static final String BODY = "body";
66         private static final String INPUT = "input";
67         
68     private static final String GENERIC_NEIGHBOR_CONFIGURATION_INPUT = "generic-neighbor-configuration-input.";
69     private static final String GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE = GENERIC_NEIGHBOR_CONFIGURATION_INPUT.concat("neighbor-list-in-use");
70         private static final String MODIFY_CONFIG_ANR = "ModifyConfigANR";
71         private static final String ANR_CHANGES_MAP_FILE_NAME = "anr-changes-from-policy-to-sdnr";
72
73     private String rootDir;
74
75     protected VelocityEngine velocityEngine;
76
77     public OofPciPocDmaapConsumers() {
78         velocityEngine = new VelocityEngine();
79         Properties props = new Properties();
80         rootDir = System.getenv(DMAAPLISTENERROOT);
81
82         if ((rootDir == null) || (rootDir.length() == 0)) {
83             rootDir = "/opt/app/dmaap-listener/lib/";
84         }
85         else {
86             rootDir = rootDir + "/lib/";
87         }
88
89         props.put("file.resource.loader.path", rootDir);
90         velocityEngine.init(props);
91     }
92
93     /*
94      * for testing purposes
95      */
96     OofPciPocDmaapConsumers(Properties props) {
97         velocityEngine = new VelocityEngine();
98         velocityEngine.init(props);
99     }
100
101     protected String publish(String templatePath, String jsonString, JsonNode configurationsOrDataNode, boolean invokePciChangesPublish, boolean invokeAnrChangesPublish) throws IOException, InvalidMessageException
102     {
103         if (invokePciChangesPublish){
104             return publishPciChangesFromPolicyToSDNR(templatePath, configurationsOrDataNode);
105         } else if (invokeAnrChangesPublish){
106             return publishANRChangesFromPolicyToSDNR(templatePath, configurationsOrDataNode);
107         } else {
108             return publishFullMessage(templatePath, jsonString);
109         }
110     }
111
112     private String publishFullMessage(String templatePath, String jsonString) throws IOException
113     {
114         JSONObject jsonObj = new JSONObject(jsonString);
115         VelocityContext context = new VelocityContext();
116         for(Object key : jsonObj.keySet())
117         {
118             context.put((String)key, jsonObj.get((String)key));
119         }
120
121         String id = jsonObj.getJSONObject(EVENT_HEADER).get("id").toString();
122         context.put("req_id", id);
123
124         context.put("curr_time", Instant.now());
125
126         ObjectMapper oMapper = new ObjectMapper();
127
128         String rpcMsgbody = oMapper.writeValueAsString(jsonString);
129         context.put("full_message", rpcMsgbody);
130
131         Writer writer = new StringWriter();
132         velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
133         writer.flush();
134
135         return writer.toString();
136     }
137     
138     private String publishANRChangesFromPolicyToSDNR(String templatePath, JsonNode dataNode) throws IOException, InvalidMessageException
139     {
140         VelocityContext context = new VelocityContext();
141         
142         String RPC_NAME_KEY_IN_VT = "rpc_name";
143         String RPC_NAME_VALUE_IN_VT = "generic-neighbor-configuration";
144         
145         String CELL_CONFIG = "CellConfig";
146         String ALIAS_LABEL = "alias";
147         String LTE = "LTE";
148         String RAN = "RAN";
149         String LTE_CELL = "LTECell";
150         String NEIGHBOR_LIST_IN_USE = "NeighborListInUse";
151         
152         JSONObject numberOfEntries = new JSONObject();
153         JSONObject alias = new JSONObject();
154         JSONArray sliParametersArray = new JSONArray();
155         
156         String aliasValue =  dataNode.get(DATA).get(FAP_SERVICE).get(ALIAS_LABEL).textValue();
157         
158         JsonNode nbrListInUse = dataNode.get(DATA).get(FAP_SERVICE).get(CELL_CONFIG).get(LTE).get(RAN).get(NEIGHBOR_LIST_IN_USE).get(LTE_CELL);
159         
160         int entryCount = 0;
161         
162         if(nbrListInUse.isArray()) {
163                 for(JsonNode lteCell:nbrListInUse) {
164                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"plmnid")
165                                 .put(STRING_VALUE, lteCell.get("PLMNID")));
166                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"cid")
167                                 .put(STRING_VALUE, lteCell.get("CID")));
168                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"phy-cell-id")
169                                 .put(STRING_VALUE, lteCell.get("PhyCellID")));
170                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"pnf-name")
171                                 .put(STRING_VALUE, lteCell.get("PNFName")));
172                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"blacklisted")
173                                 .put(STRING_VALUE, lteCell.get("Blacklisted")));
174                         
175                         entryCount++;
176                 }
177                 
178                 alias.put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT+ALIAS_LABEL);
179             alias.put(STRING_VALUE, aliasValue);
180             
181             numberOfEntries.put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT+"number-of-neighbor-cell-entries");
182             numberOfEntries.put(STRING_VALUE, entryCount);
183             
184             sliParametersArray.put(alias);
185             sliParametersArray.put(numberOfEntries);
186             
187             context.put(SLI_PARAMETERS, sliParametersArray);
188             
189             context.put(RPC_NAME_KEY_IN_VT, RPC_NAME_VALUE_IN_VT);
190
191             Writer writer = new StringWriter();
192             velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
193             writer.flush();
194
195             return writer.toString();
196                 
197         }else {
198                 throw new InvalidMessageException("nbrListInUse is not of Type Array. Could not read neighbor list elements");
199         }
200         
201     }
202     
203     private String publishPciChangesFromPolicyToSDNR(String templatePath, JsonNode configurationsJsonNode) throws IOException, InvalidMessageException
204     {
205         String RPC_NAME_KEY_IN_VT = "rpc_name";
206         String RPC_NAME_VALUE_IN_VT = "configuration-phy-cell-id";
207         String ALIAS = "alias";
208         String X0005b9Lte = "X0005b9Lte";
209         
210         VelocityContext context = new VelocityContext();
211         
212         JSONObject numberOfEntries = new JSONObject();
213         JSONArray sliParametersArray = new JSONArray();
214         
215         JsonNode configurations = configurationsJsonNode.get(CONFIGURATIONS);
216         
217         int entryCount = 0;
218         
219         if(configurations.isArray()) {
220                 for(JsonNode dataNode:configurations) {
221                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+ALIAS)
222                                 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(ALIAS)));
223                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"cid")
224                                 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get("CellConfig").get("LTE").get("RAN").get("Common").get("CellIdentity")));
225                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"phy-cell-id-in-use")
226                                 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(X0005b9Lte).get("phyCellIdInUse")));
227                         sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"pnf-name")
228                                 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(X0005b9Lte).get("pnfName")));
229                         entryCount++;
230                 }
231             
232             numberOfEntries.put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"-number-of-entries");
233             numberOfEntries.put(STRING_VALUE, entryCount);
234             
235             sliParametersArray.put(numberOfEntries);
236             
237             context.put(SLI_PARAMETERS, sliParametersArray);
238             
239             context.put(RPC_NAME_KEY_IN_VT, RPC_NAME_VALUE_IN_VT);
240
241             Writer writer = new StringWriter();
242             velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
243             writer.flush();
244
245             return writer.toString();
246                 
247         }else {
248                 throw new InvalidMessageException("Configurations is not of Type Array. Could not read configuration changes");
249         }
250         
251     }
252
253     @Override
254     public void processMsg(String msg) throws InvalidMessageException {
255
256         if (msg == null) {
257             throw new InvalidMessageException("Null message");
258         }
259
260         ObjectMapper oMapper = new ObjectMapper();
261         JsonNode dmaapMessageRootNode;
262         try {
263                 dmaapMessageRootNode = oMapper.readTree(msg);
264         } catch (Exception e) {
265             throw new InvalidMessageException("Cannot parse json object", e);
266         }
267         
268
269         JsonNode rpcnameNode = dmaapMessageRootNode.get(RPC_NAME);
270         if(rpcnameNode == null) {
271                  LOG.info("Unable to identify the respective consumer to invoke. Please verify the dmaap message..");
272                  return;
273         }
274         
275         String rpcname = rpcnameNode.textValue();
276         
277         if(!MODIFY_CONFIG.toLowerCase().equals(rpcname) && !MODIFY_CONFIG_ANR.toLowerCase().equals(rpcname)) {
278             LOG.info("Unknown rpc name {}", rpcname);
279             return;
280         }
281         
282         if(MODIFY_CONFIG.toLowerCase().equals(rpcname)) {
283                 invokePCIChangesConsumer(dmaapMessageRootNode, oMapper, msg);
284             return;
285         }
286         
287         if(MODIFY_CONFIG_ANR.toLowerCase().equals(rpcname)) {
288                 invokeANRChangesConsumer(dmaapMessageRootNode, oMapper, msg);
289             return;
290         }
291     
292     }
293
294     private void invokeANRChangesConsumer(JsonNode dmaapMessageRootNode, ObjectMapper oMapper,
295                         String msg) throws InvalidMessageException {
296         JsonNode body = dmaapMessageRootNode.get(BODY);
297         if(body == null) {
298                  LOG.info("Missing body node.");
299                  return;
300         }
301         
302         JsonNode input = body.get(INPUT);
303         if(input == null) {
304                  LOG.info("Missing input node.");
305                  return;
306         }
307         
308         JsonNode action = input.get(ACTION);
309         if(action == null) {
310                  LOG.info("Missing action node.");
311                  return;
312         }
313         
314         if(!MODIFY_CONFIG_ANR.equals(action.textValue())) {
315             LOG.info("Unknown Action {}", action);
316             return;
317         }
318         
319         JsonNode payload = input.get(PAYLOAD);
320         if(payload == null) {
321             LOG.info("Missing payload node.");
322             return;
323         }
324
325         String payloadText = payload.asText();
326         
327         if(!payloadText.contains(CONFIGURATIONS)) {
328          LOG.info("Missing configurations node.");
329          return;
330        }
331         
332        JsonNode configurationsJsonNode;
333             try {
334                 configurationsJsonNode = oMapper.readTree(payloadText);
335             } catch (Exception e) {
336                 throw new InvalidMessageException("Cannot parse payload value", e);
337             }
338
339         String mapFilename = rootDir + ANR_CHANGES_MAP_FILE_NAME + ".map";
340         Map<String, String> fieldMap = loadMap(mapFilename);
341         if (fieldMap == null) {
342             return;
343         }
344
345         if (!fieldMap.containsKey(SDNC_ENDPOINT)) {
346             return;
347         }
348         String sdncEndpoint = fieldMap.get(SDNC_ENDPOINT);
349
350         if (!fieldMap.containsKey(TEMPLATE)) {
351             throw new InvalidMessageException("No SDNC template known for message ");
352         }
353         String templateName = fieldMap.get(TEMPLATE);
354         
355         JsonNode configurations = configurationsJsonNode.get(CONFIGURATIONS);
356         
357         if(configurations.isArray()) {
358                 for(JsonNode dataNode:configurations) {
359                 if(dataNode.get(DATA).get(FAP_SERVICE) == null) {
360                     LOG.info("Could not make a rpc call. Missing fapService node for dataNode element::", dataNode.textValue());
361                 }else {
362                         buildAndInvokeANRChangesRPC(sdncEndpoint, templateName,msg, dataNode);
363                 }
364                 }
365         }else {
366                 throw new InvalidMessageException("Configurations is not of Type Array. Could not read configuration changes");
367         }
368         }
369
370         private void invokePCIChangesConsumer(JsonNode dmaapMessageRootNode, ObjectMapper oMapper,
371                         String msg) throws InvalidMessageException {
372                 JsonNode body = dmaapMessageRootNode.get(BODY);
373         if(body == null) {
374                  LOG.info("Missing body node.");
375                  return;
376         }
377         
378         JsonNode input = body.get(INPUT);
379         if(input == null) {
380                  LOG.info("Missing input node.");
381                  return;
382         }
383         
384         JsonNode action = input.get(ACTION);
385         if(action == null) {
386                  LOG.info("Missing action node.");
387                  return;
388         }
389         
390         if(!MODIFY_CONFIG.equals(action.textValue())) {
391             LOG.info("Unknown Action {}", action);
392             return;
393         }
394         
395         JsonNode payload = input.get(PAYLOAD);
396         if(payload == null) {
397             LOG.info("Missing payload node.");
398             return;
399         }
400
401         String configurations = payload.asText();
402         
403         if(!configurations.contains(CONFIGURATIONS)) {
404          LOG.info("Missing configurations node.");
405          return;
406        }
407         
408        JsonNode configurationsJsonNode;
409             try {
410                 configurationsJsonNode = oMapper.readTree(configurations);
411             } catch (Exception e) {
412                 throw new InvalidMessageException("Cannot parse payload value", e);
413             }
414
415         String mapFilename = rootDir + PCI_CHANGES_MAP_FILE_NAME + ".map";
416         Map<String, String> fieldMap = loadMap(mapFilename);
417         if (fieldMap == null) {
418             return;
419         }
420
421         if (!fieldMap.containsKey(SDNC_ENDPOINT)) {
422             return;
423         }
424         String sdncEndpoint = fieldMap.get(SDNC_ENDPOINT);
425
426         if (!fieldMap.containsKey(TEMPLATE)) {
427             throw new InvalidMessageException("No SDNC template known for message ");
428         }
429         String templateName = fieldMap.get(TEMPLATE);
430         
431         buildAndInvokePCIChangesRPC(sdncEndpoint, templateName, msg, configurationsJsonNode);
432         }
433
434         private void buildAndInvokePCIChangesRPC(String sdncEndpoint, String templateName, String msg, JsonNode configurationsOrDataNode) {
435                 try {
436             String rpcMsgbody = publish(templateName, msg, configurationsOrDataNode, true, false);
437             String odlUrlBase = getProperty("sdnc.odl.url-base");
438             String odlUser = getProperty("sdnc.odl.user");
439             String odlPassword = getProperty("sdnc.odl.password");
440
441             if ((odlUrlBase != null) && (odlUrlBase.length() > 0)) {
442                 SdncOdlConnection conn = SdncOdlConnection.newInstance(odlUrlBase + "/" + sdncEndpoint, odlUser, odlPassword);
443
444                 conn.send("POST", "application/json", rpcMsgbody);
445             } else {
446                 LOG.info("POST message body would be:\n" + rpcMsgbody);
447             }
448         } catch (Exception e) {
449             LOG.error("Unable to process message", e);
450         }
451         }
452         
453         private void buildAndInvokeANRChangesRPC(String sdncEndpoint, String templateName, String msg, JsonNode configurationsOrDataNode) {
454                 try {
455             String rpcMsgbody = publish(templateName, msg, configurationsOrDataNode, false, true);
456             String odlUrlBase = getProperty("sdnc.odl.url-base");
457             String odlUser = getProperty("sdnc.odl.user");
458             String odlPassword = getProperty("sdnc.odl.password");
459
460             if ((odlUrlBase != null) && (odlUrlBase.length() > 0)) {
461                 SdncOdlConnection conn = SdncOdlConnection.newInstance(odlUrlBase + "/" + sdncEndpoint, odlUser, odlPassword);
462
463                 conn.send("POST", "application/json", rpcMsgbody);
464             } else {
465                 LOG.info("POST message body would be:\n" + rpcMsgbody);
466             }
467         } catch (Exception e) {
468             LOG.error("Unable to process message", e);
469         }
470         }
471
472         private Map<String, String> loadMap(String mapFilename) {
473         File mapFile = new File(mapFilename);
474
475         if (!mapFile.canRead()) {
476             LOG.error(String.format("Cannot read map file (%s)", mapFilename));
477             return null;
478         }
479
480         Map<String, String> results = new HashMap<>();
481         try (BufferedReader mapReader = new BufferedReader(new FileReader(mapFile))) {
482
483             String curLine;
484
485             while ((curLine = mapReader.readLine()) != null) {
486                 curLine = curLine.trim();
487
488                 if ((curLine.length() > 0) && (!curLine.startsWith("#")) && curLine.contains("=>")) {
489                     String[] entry = curLine.split("=>");
490                     if (entry.length == 2) {
491                         results.put(entry[0].trim(), entry[1].trim());
492                     }
493                 }
494             }
495             mapReader.close();
496         } catch (Exception e) {
497             LOG.error("Caught exception reading map " + mapFilename, e);
498             return null;
499         }
500
501         return results;
502     }
503
504 }