2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=========================================================
18 package org.onap.ccsdk.sli.core.slipluginutils;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.gson.JsonArray;
22 import com.google.gson.JsonElement;
23 import com.google.gson.JsonObject;
24 import com.google.gson.JsonParser;
25 import org.apache.commons.lang3.StringUtils;
26 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
27 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
28 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
29 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.JsonParserHelper;
30 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.graph.DijkstraGraphSearch;
31 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.graph.Graph;
32 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.graph.Path;
33 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.topology.*;
34 import org.onap.ccsdk.sli.core.slipluginutils.slitopologyutils.topology.LogicalLink;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import java.util.ArrayList;
39 import java.util.List;
42 public class SliTopologyUtils implements SvcLogicJavaPlugin {
43 private static final Logger LOG = LoggerFactory.getLogger(SliTopologyUtils.class);
44 public static final String SUCCESS_CONSTANT = "success";
45 public static final String FAILURE_CONSTANT = "failure";
46 public static final String NOT_FOUND_CONSTANT = "not-found";
49 public SliTopologyUtils(){};
51 * Provides simple path computation functionality to Directed Graphs.
53 * @param parameters HashMap<String,String> of parameters passed by the DG to this function
55 * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
57 * <tr><td>pnfs-pfx</td><td>Mandatory</td><td>Prefix in context memory to get the pnf attributes from.</td></tr>
58 * <tr><td>links-pfx</td><td>Mandatory</td><td>Prefix in context memory to get the link attributes from.</td></tr>
59 * <tr><td>src-node</td><td>Mandatory</td><td>Source pnf name.</td></tr>
60 * <tr><td>dst-node</td><td>Mandatory</td><td>Destination pnf name.</td></tr>
61 * <tr><td>response-pfx</td><td>Mandatory</td><td>Prefix in context memory to populate the resulting attributes in.</td></tr>
62 * <tr><td>output-end-to-end-path</td><td>Optional</td><td>true or false to output end to end full path. If not included, only output cross domain path</td></tr>
65 * @param ctx Reference to context memory
66 * @throws SvcLogicException
68 public static String computePath(Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
70 LOG.debug( "ENTERING Execute Node \"computePath\"" );
72 // Validate, Log, & read parameters
73 checkParameters(parameters, new String[]{ "pnfs-pfx", "links-pfx",
74 "src-node", "dst-node", "response-pfx"}, LOG);
76 boolean outputFullPath = false;
77 String outputEndToEnd = parameters.get("output-end-to-end-path");
79 if (outputEndToEnd != null && outputEndToEnd.equals("true")){
80 outputFullPath = true;
81 LOG.debug( "OutputEndToEndPath enabled");
84 String pnfsStr = ctx.toJsonString(parameters.get("pnfs-pfx"));
85 String lkStr = ctx.toJsonString(parameters.get("links-pfx"));
87 if (pnfsStr.isEmpty()){
88 LOG.warn("Pnf Array attributes are empty");
89 throw new Exception( "Pnf Array attributes are empty");
93 LOG.warn("Logical-links Array attributes are empty");
94 throw new Exception( "Logical-links Array attributes are empty");
97 LOG.debug("Pnf Json String is: {}", pnfsStr);
99 String srcNodeStr = parameters.get("src-node");
100 String dstNodeStr = parameters.get("dst-node");
102 if( srcNodeStr.isEmpty() || dstNodeStr.isEmpty()){
103 LOG.warn("Src or Dst node is empty");
104 throw new Exception("Src or Dst node is empty");
107 JsonParser jp = new JsonParser();
109 JsonArray pnfArr = ((JsonObject) jp.parse(pnfsStr)).getAsJsonArray("pnf");
110 JsonArray lkArr = ((JsonObject) jp.parse(lkStr)).getAsJsonArray("logical-link");
111 LOG.debug("Creating graph with {} pnf(s) and {} link(s)", pnfArr.size(), lkArr.size());
112 Graph<Pnf, LogicalLink> graph = buildGraph(pnfArr, lkArr);
114 Pnf src = new Pnf(srcNodeStr);
115 Pnf dst = new Pnf(dstNodeStr);
117 if (!graph.getVertexes().contains(src) || !graph.getVertexes().contains(dst)){
118 LOG.warn("Src or Dst node doesn't exist");
119 throw new Exception("Src or Dst node doesn't exist");
122 DijkstraGraphSearch.Result result =
123 new DijkstraGraphSearch<Pnf, LogicalLink>().search(graph, src, dst,null, -1);
124 LOG.debug("Path Computing results: {}", result.paths().toString());
126 if (result.paths().size() > 0){
127 JsonObject root = new JsonObject();
128 JsonArray solnList = new JsonArray();
130 Path<Pnf, LogicalLink> path = (Path<Pnf, LogicalLink>) result.paths().iterator().next();
131 for (LogicalLink logicalLink : path.edges()) {
132 if ( ((OtnLink) logicalLink.underlayLink()).isInnerDomain() && !outputFullPath ){
133 //Ignore inner domain links
135 JsonObject curLink = new JsonObject();
136 String srcNode = logicalLink.src().toString();
137 String dstNode = logicalLink.dst().toString();
138 String srcPInterface = ((OtnLink) logicalLink.underlayLink()).src().pInterfaceName().getName();
139 String dstPInterface = ((OtnLink) logicalLink.underlayLink()).dst().pInterfaceName().getName();
140 String linkName = ((OtnLink) logicalLink.underlayLink()).linkName();
141 curLink.addProperty("src_node", srcNode);
142 curLink.addProperty("dst_node", dstNode);
143 curLink.addProperty("src_pinterface", srcPInterface);
144 curLink.addProperty("dst_pinterface", dstPInterface);
145 curLink.addProperty("original_link", linkName);
147 solnList.add(curLink);
150 root.add("solutions", solnList);
151 //Write result back to context memory;
152 String pp = parameters.get("response-pfx").isEmpty() ? "" : parameters.get("response-pfx") + ".";
153 Map<String, String> mm = null;
154 mm = JsonParserHelper.convertToProperties(root.toString());
156 for (Map.Entry<String, String> entry : mm.entrySet()) {
157 ctx.setAttribute(pp + entry.getKey(), entry.getValue());
160 LOG.debug("SliTopologyUtils: path computation succeeds in finding the shortest path;" +
161 " result has been written back into context memory.");
162 return SUCCESS_CONSTANT;
164 LOG.debug("SliTopologyUtils: no valid path found.");
165 return NOT_FOUND_CONSTANT;
168 } catch( Exception e ) {
169 throw new SvcLogicException( "An error occurred in the computePath Execute node", e );
171 LOG.debug( "EXITING Execute Node \"computePath\"" );
175 private static Graph<Pnf, LogicalLink> buildGraph(JsonArray pnfs, JsonArray llks) {
176 ImmutableSet.Builder pnfSetBlder = ImmutableSet.builder();
177 ImmutableSet.Builder lkSetBlder = ImmutableSet.builder();
179 //Create Immutable set of Pnf;
180 for (int i = 0,e = pnfs.size(); i < e; i++){
181 JsonElement pnfName = ((JsonObject) pnfs.get(i)).get("pnf-name");
183 if (pnfName != null){
184 String pnfNameStr = pnfName.getAsString();
186 if (pnfNameStr != null && !pnfNameStr.isEmpty()){
187 pnfSetBlder.add(new Pnf(pnfNameStr));
191 LOG.debug("SliTopologyUtils: invalid pnf: {}", ((JsonObject) pnfs.get(i)).toString());
195 //Create Immutable set of Logical-Link
196 for (int i = 0,e = llks.size(); i < e; i++){
197 JsonObject lkRoot = ((JsonObject) llks.get(i));
198 JsonElement relationList = lkRoot.get("relationship-list");
200 if (relationList != null) {
201 JsonElement relationListArray = ((JsonObject) relationList).get("relationship");
203 if (relationListArray != null){
204 List<String> pnfNameStrList = new ArrayList<>();
205 List<String> pInterfaceStrList= new ArrayList<>();
207 for (int j = 0,k = ((JsonArray) relationListArray).size(); j < k; j++){
208 JsonObject relation = ((JsonArray) relationListArray).get(j).getAsJsonObject();
209 JsonElement relatedTo = relation.getAsJsonPrimitive("related-to");
211 if (relatedTo != null && relatedTo.getAsString().equals("p-interface")){
212 JsonArray data = relation.getAsJsonArray("relationship-data");
213 for (int m = 0, n = data.size(); m < n; m++){
214 JsonObject dataKeyValue = data.get(m).getAsJsonObject();
216 if (dataKeyValue.get("relationship-key").getAsString().equals("pnf.pnf-name")){
217 pnfNameStrList.add(dataKeyValue.get("relationship-value").getAsString());
218 } else if (dataKeyValue.get("relationship-key").getAsString()
219 .equals("p-interface.interface-name")){
220 pInterfaceStrList.add(dataKeyValue.get("relationship-value").getAsString());
226 if (pnfNameStrList.size() == 2 && pnfNameStrList.size() == 2){
227 String pnf1NameStr = pnfNameStrList.get(0);
228 String pnf2NameStr = pnfNameStrList.get(1);
229 String pI1NameStr = pInterfaceStrList.get(0);
230 String pI2NameStr = pInterfaceStrList.get(1);
231 Pnf pnf1 = new Pnf(pnf1NameStr);
232 Pnf pnf2 = new Pnf(pnf2NameStr);
233 PInterfaceName pI1Name = PInterfaceName.of(pI1NameStr);
234 PInterfaceName pI2Name = PInterfaceName.of(pI2NameStr);
235 PInterface pI1 = new PInterface(pnf1NameStr, pI1Name);
236 PInterface pI2 = new PInterface(pnf1NameStr, pI2Name);
237 String linkName_f = pI1Name.getNetworkId() + "-linkId-"
238 + pI1Name.getPnfId() + "-"
239 + pI1Name.getLtpId();
240 String linkName_b = pI2Name.getNetworkId()
241 + "-linkId-" + pI2Name.getPnfId()
242 + "-" + pI2Name.getLtpId();
243 OtnLink link_f = new OtnLink(linkName_f, pI1, pI2);
244 OtnLink link_b = new OtnLink(linkName_b, pI2, pI1);
245 lkSetBlder.add(new LogicalLink(pnf1, pnf2, link_f));
246 lkSetBlder.add(new LogicalLink(pnf2, pnf1, link_b));
251 return new Graph<Pnf, LogicalLink>(pnfSetBlder.build(), lkSetBlder.build());
255 * Throws an exception and writes an error to the log file if a required
256 * parameters is not found in the parametersMap.
258 * Use at the beginning of functions that can be called by Directed Graphs
259 * and can take parameters to verify that all parameters have been provided
260 * by the Directed Graph.
261 * @param parametersMap parameters Map passed to this node
262 * @param requiredParams Array of parameters required by the calling function
263 * @param log Reference to Logger to log to
264 * @throws SvcLogicException if a String in the requiredParams array is
265 * not a key in parametersMap.
268 public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log) throws SvcLogicException {
269 if( requiredParams == null || requiredParams.length < 1){
270 log.debug("required parameters was empty, exiting early.");
273 if (parametersMap == null || parametersMap.keySet().isEmpty()){
274 String errorMessage = "This method requires the parameters [" + StringUtils.join(requiredParams,",") + "], but no parameters were passed in.";
275 log.error(errorMessage);
276 throw new SvcLogicException(errorMessage);
279 for (String param : requiredParams) {
280 if (!parametersMap.containsKey(param)) {
281 String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
282 log.error(errorMessage);
283 log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
284 throw new SvcLogicException(errorMessage);