2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.ccsdk.sli.northbound.dmaapclient;
24 import java.io.BufferedReader;
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;
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;
43 public class OofPciPocDmaapConsumers extends SdncDmaapConsumerImpl {
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";
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";
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";
68 private static final String EMPTY = "";
69 private static final String ESCAPE_SEQUENCE_QUOTES = "\"";
71 private static final String GENERIC_NEIGHBOR_CONFIGURATION_INPUT = "generic-neighbor-configuration-input.";
72 private static final String GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE = GENERIC_NEIGHBOR_CONFIGURATION_INPUT.concat("neighbor-list-in-use");
73 private static final String MODIFY_CONFIG_ANR = "ModifyConfigANR";
74 private static final String ANR_CHANGES_MAP_FILE_NAME = "anr-changes-from-policy-to-sdnr";
76 private String rootDir;
78 protected VelocityEngine velocityEngine;
80 public OofPciPocDmaapConsumers() {
81 velocityEngine = new VelocityEngine();
82 Properties props = new Properties();
83 rootDir = System.getenv(DMAAPLISTENERROOT);
85 if ((rootDir == null) || (rootDir.length() == 0)) {
86 rootDir = "/opt/app/dmaap-listener/lib/";
89 rootDir = rootDir + "/lib/";
92 props.put("file.resource.loader.path", rootDir);
93 velocityEngine.init(props);
97 * for testing purposes
99 OofPciPocDmaapConsumers(Properties props) {
100 velocityEngine = new VelocityEngine();
101 velocityEngine.init(props);
104 protected String publish(String templatePath, String jsonString, JsonNode configurationsOrDataNode, boolean invokePciChangesPublish, boolean invokeAnrChangesPublish) throws IOException, InvalidMessageException
106 if (invokePciChangesPublish){
107 return publishPciChangesFromPolicyToSDNR(templatePath, configurationsOrDataNode);
108 } else if (invokeAnrChangesPublish){
109 return publishANRChangesFromPolicyToSDNR(templatePath, configurationsOrDataNode);
111 return publishFullMessage(templatePath, jsonString);
115 private String publishFullMessage(String templatePath, String jsonString) throws IOException
117 JSONObject jsonObj = new JSONObject(jsonString);
118 VelocityContext context = new VelocityContext();
119 for(Object key : jsonObj.keySet())
121 context.put((String)key, jsonObj.get((String)key));
124 String id = jsonObj.getJSONObject(EVENT_HEADER).get("id").toString();
125 context.put("req_id", id);
127 context.put("curr_time", Instant.now());
129 ObjectMapper oMapper = new ObjectMapper();
131 String rpcMsgbody = oMapper.writeValueAsString(jsonString);
132 context.put("full_message", rpcMsgbody);
134 Writer writer = new StringWriter();
135 velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
138 return writer.toString();
141 private String publishANRChangesFromPolicyToSDNR(String templatePath, JsonNode dataNode) throws IOException, InvalidMessageException
143 VelocityContext context = new VelocityContext();
145 String RPC_NAME_KEY_IN_VT = "rpc_name";
146 String RPC_NAME_VALUE_IN_VT = "generic-neighbor-configuration";
148 String CELL_CONFIG = "CellConfig";
149 String ALIAS_LABEL = "alias";
152 String LTE_CELL = "LTECell";
153 String NEIGHBOR_LIST_IN_USE = "NeighborListInUse";
155 JSONObject numberOfEntries = new JSONObject();
156 JSONObject alias = new JSONObject();
157 JSONArray sliParametersArray = new JSONArray();
159 String aliasValue = dataNode.get(DATA).get(FAP_SERVICE).get(ALIAS_LABEL).textValue();
161 JsonNode nbrListInUse = dataNode.get(DATA).get(FAP_SERVICE).get(CELL_CONFIG).get(LTE).get(RAN).get(NEIGHBOR_LIST_IN_USE).get(LTE_CELL);
165 if(nbrListInUse.isArray()) {
166 for(JsonNode lteCell:nbrListInUse) {
167 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"plmnid")
168 .put(STRING_VALUE, lteCell.get("PLMNID").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
169 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"cid")
170 .put(STRING_VALUE, lteCell.get("CID").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
171 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"phy-cell-id")
172 .put(STRING_VALUE, lteCell.get("PhyCellID").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
173 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"pnf-name")
174 .put(STRING_VALUE, lteCell.get("PNFName").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
175 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT_NEIGHBOR_LIST_IN_USE+"["+entryCount+"]."+"blacklisted")
176 .put(STRING_VALUE, lteCell.get("Blacklisted").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
181 alias.put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT+ALIAS_LABEL);
182 alias.put(STRING_VALUE, aliasValue);
184 numberOfEntries.put(PARAMETER_NAME, GENERIC_NEIGHBOR_CONFIGURATION_INPUT+"number-of-neighbor-cell-entries");
185 numberOfEntries.put(STRING_VALUE, entryCount);
187 sliParametersArray.put(alias);
188 sliParametersArray.put(numberOfEntries);
190 context.put(SLI_PARAMETERS, sliParametersArray);
192 context.put(RPC_NAME_KEY_IN_VT, RPC_NAME_VALUE_IN_VT);
194 Writer writer = new StringWriter();
195 velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
198 return writer.toString();
201 throw new InvalidMessageException("nbrListInUse is not of Type Array. Could not read neighbor list elements");
206 private String publishPciChangesFromPolicyToSDNR(String templatePath, JsonNode configurationsJsonNode) throws IOException, InvalidMessageException
208 String RPC_NAME_KEY_IN_VT = "rpc_name";
209 String RPC_NAME_VALUE_IN_VT = "configuration-phy-cell-id";
210 String ALIAS = "alias";
211 String X0005b9Lte = "X0005b9Lte";
213 VelocityContext context = new VelocityContext();
215 JSONObject numberOfEntries = new JSONObject();
216 JSONArray sliParametersArray = new JSONArray();
218 JsonNode configurations = configurationsJsonNode.get(CONFIGURATIONS);
222 if(configurations.isArray()) {
223 for(JsonNode dataNode:configurations) {
224 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+ALIAS)
225 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(ALIAS).toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
226 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"cid")
227 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get("CellConfig").get("LTE").get("RAN").get("Common").get("CellIdentity").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
228 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"phy-cell-id-in-use")
229 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(X0005b9Lte).get("phyCellIdInUse").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
230 sliParametersArray.put(new JSONObject().put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"["+entryCount+"]."+"pnf-name")
231 .put(STRING_VALUE, dataNode.get(DATA).get(FAP_SERVICE).get(X0005b9Lte).get("pnfName").toString().replace(ESCAPE_SEQUENCE_QUOTES, EMPTY)));
235 numberOfEntries.put(PARAMETER_NAME, PHYSICAL_CELL_ID_INPUT_FAP_SERVICE+"-number-of-entries");
236 numberOfEntries.put(STRING_VALUE, entryCount);
238 sliParametersArray.put(numberOfEntries);
240 context.put(SLI_PARAMETERS, sliParametersArray);
242 context.put(RPC_NAME_KEY_IN_VT, RPC_NAME_VALUE_IN_VT);
244 Writer writer = new StringWriter();
245 velocityEngine.mergeTemplate(templatePath, UTF_8, context, writer);
248 return writer.toString();
251 throw new InvalidMessageException("Configurations is not of Type Array. Could not read configuration changes");
257 public void processMsg(String msg) throws InvalidMessageException {
260 throw new InvalidMessageException("Null message");
263 ObjectMapper oMapper = new ObjectMapper();
264 JsonNode dmaapMessageRootNode;
266 dmaapMessageRootNode = oMapper.readTree(msg);
267 } catch (Exception e) {
268 throw new InvalidMessageException("Cannot parse json object", e);
272 JsonNode rpcnameNode = dmaapMessageRootNode.get(RPC_NAME);
273 if(rpcnameNode == null) {
274 LOG.info("Unable to identify the respective consumer to invoke. Please verify the dmaap message..");
278 String rpcname = rpcnameNode.textValue();
280 if(!MODIFY_CONFIG.toLowerCase().equals(rpcname) && !MODIFY_CONFIG_ANR.toLowerCase().equals(rpcname)) {
281 LOG.info("Unknown rpc name {}", rpcname);
285 if(MODIFY_CONFIG.toLowerCase().equals(rpcname)) {
286 invokePCIChangesConsumer(dmaapMessageRootNode, oMapper, msg);
290 if(MODIFY_CONFIG_ANR.toLowerCase().equals(rpcname)) {
291 invokeANRChangesConsumer(dmaapMessageRootNode, oMapper, msg);
297 private void invokeANRChangesConsumer(JsonNode dmaapMessageRootNode, ObjectMapper oMapper,
298 String msg) throws InvalidMessageException {
299 JsonNode body = dmaapMessageRootNode.get(BODY);
301 LOG.info("Missing body node.");
305 JsonNode input = body.get(INPUT);
307 LOG.info("Missing input node.");
311 JsonNode action = input.get(ACTION);
313 LOG.info("Missing action node.");
317 if(!MODIFY_CONFIG_ANR.equals(action.textValue())) {
318 LOG.info("Unknown Action {}", action);
322 JsonNode payload = input.get(PAYLOAD);
323 if(payload == null) {
324 LOG.info("Missing payload node.");
328 String payloadText = payload.asText();
330 if(!payloadText.contains(CONFIGURATIONS)) {
331 LOG.info("Missing configurations node.");
335 JsonNode configurationsJsonNode;
337 configurationsJsonNode = oMapper.readTree(payloadText);
338 } catch (Exception e) {
339 throw new InvalidMessageException("Cannot parse payload value", e);
342 String mapFilename = rootDir + ANR_CHANGES_MAP_FILE_NAME + ".map";
343 Map<String, String> fieldMap = loadMap(mapFilename);
344 if (fieldMap == null) {
348 if (!fieldMap.containsKey(SDNC_ENDPOINT)) {
351 String sdncEndpoint = fieldMap.get(SDNC_ENDPOINT);
353 if (!fieldMap.containsKey(TEMPLATE)) {
354 throw new InvalidMessageException("No SDNC template known for message ");
356 String templateName = fieldMap.get(TEMPLATE);
358 JsonNode configurations = configurationsJsonNode.get(CONFIGURATIONS);
360 if(configurations.isArray()) {
361 for(JsonNode dataNode:configurations) {
362 if(dataNode.get(DATA).get(FAP_SERVICE) == null) {
363 LOG.info("Could not make a rpc call. Missing fapService node for dataNode element::", dataNode.textValue());
365 buildAndInvokeANRChangesRPC(sdncEndpoint, templateName,msg, dataNode);
369 throw new InvalidMessageException("Configurations is not of Type Array. Could not read configuration changes");
373 private void invokePCIChangesConsumer(JsonNode dmaapMessageRootNode, ObjectMapper oMapper,
374 String msg) throws InvalidMessageException {
375 JsonNode body = dmaapMessageRootNode.get(BODY);
377 LOG.info("Missing body node.");
381 JsonNode input = body.get(INPUT);
383 LOG.info("Missing input node.");
387 JsonNode action = input.get(ACTION);
389 LOG.info("Missing action node.");
393 if(!MODIFY_CONFIG.equals(action.textValue())) {
394 LOG.info("Unknown Action {}", action);
398 JsonNode payload = input.get(PAYLOAD);
399 if(payload == null) {
400 LOG.info("Missing payload node.");
404 String configurations = payload.asText();
406 if(!configurations.contains(CONFIGURATIONS)) {
407 LOG.info("Missing configurations node.");
411 JsonNode configurationsJsonNode;
413 configurationsJsonNode = oMapper.readTree(configurations);
414 } catch (Exception e) {
415 throw new InvalidMessageException("Cannot parse payload value", e);
418 String mapFilename = rootDir + PCI_CHANGES_MAP_FILE_NAME + ".map";
419 Map<String, String> fieldMap = loadMap(mapFilename);
420 if (fieldMap == null) {
424 if (!fieldMap.containsKey(SDNC_ENDPOINT)) {
427 String sdncEndpoint = fieldMap.get(SDNC_ENDPOINT);
429 if (!fieldMap.containsKey(TEMPLATE)) {
430 throw new InvalidMessageException("No SDNC template known for message ");
432 String templateName = fieldMap.get(TEMPLATE);
434 buildAndInvokePCIChangesRPC(sdncEndpoint, templateName, msg, configurationsJsonNode);
437 private void buildAndInvokePCIChangesRPC(String sdncEndpoint, String templateName, String msg, JsonNode configurationsOrDataNode) {
439 String rpcMsgbody = publish(templateName, msg, configurationsOrDataNode, true, false);
440 String odlUrlBase = getProperty("sdnc.odl.url-base");
441 String odlUser = getProperty("sdnc.odl.user");
442 String odlPassword = getProperty("sdnc.odl.password");
444 if ((odlUrlBase != null) && (odlUrlBase.length() > 0)) {
445 SdncOdlConnection conn = SdncOdlConnection.newInstance(odlUrlBase + "/" + sdncEndpoint, odlUser, odlPassword);
447 conn.send("POST", "application/json", rpcMsgbody);
449 LOG.info("POST message body would be:\n" + rpcMsgbody);
451 } catch (Exception e) {
452 LOG.error("Unable to process message", e);
456 private void buildAndInvokeANRChangesRPC(String sdncEndpoint, String templateName, String msg, JsonNode configurationsOrDataNode) {
458 String rpcMsgbody = publish(templateName, msg, configurationsOrDataNode, false, true);
459 String odlUrlBase = getProperty("sdnc.odl.url-base");
460 String odlUser = getProperty("sdnc.odl.user");
461 String odlPassword = getProperty("sdnc.odl.password");
463 if ((odlUrlBase != null) && (odlUrlBase.length() > 0)) {
464 SdncOdlConnection conn = SdncOdlConnection.newInstance(odlUrlBase + "/" + sdncEndpoint, odlUser, odlPassword);
466 conn.send("POST", "application/json", rpcMsgbody);
468 LOG.info("POST message body would be:\n" + rpcMsgbody);
470 } catch (Exception e) {
471 LOG.error("Unable to process message", e);
475 private Map<String, String> loadMap(String mapFilename) {
476 File mapFile = new File(mapFilename);
478 if (!mapFile.canRead()) {
479 LOG.error(String.format("Cannot read map file (%s)", mapFilename));
483 Map<String, String> results = new HashMap<>();
484 try (BufferedReader mapReader = new BufferedReader(new FileReader(mapFile))) {
488 while ((curLine = mapReader.readLine()) != null) {
489 curLine = curLine.trim();
491 if ((curLine.length() > 0) && (!curLine.startsWith("#")) && curLine.contains("=>")) {
492 String[] entry = curLine.split("=>");
493 if (entry.length == 2) {
494 results.put(entry[0].trim(), entry[1].trim());
499 } catch (Exception e) {
500 LOG.error("Caught exception reading map " + mapFilename, e);