Adding UI extensibility
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / viewandinspect / services / VisualizationTransformer.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 package org.onap.aai.sparky.viewandinspect.services;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.UUID;
31
32 import org.onap.aai.cl.api.Logger;
33 import org.onap.aai.cl.eelf.LoggerFactory;
34 import org.onap.aai.sparky.logging.AaiUiMsgs;
35 import org.onap.aai.sparky.util.ConfigHelper;
36 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
37 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
38 import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
39 import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
40 import org.onap.aai.sparky.viewandinspect.entity.JsonNode;
41 import org.onap.aai.sparky.viewandinspect.entity.JsonNodeLink;
42 import org.onap.aai.sparky.viewandinspect.entity.NodeDebug;
43
44 import com.fasterxml.jackson.core.JsonProcessingException;
45 import com.fasterxml.jackson.databind.ObjectMapper;
46 import com.fasterxml.jackson.databind.ObjectWriter;
47
48 /**
49  * The idea here is to receive a collection of graphs and then fold them together (or not) based on
50  * configuration. The first goal will be to fold all like-resources together, but the choice of
51  * folding could/should be configurable, and will simply change the degree of link based nodes when
52  * we generate the Node-Array and Link-Array output.
53  * 
54  * @author DAVEA
55  *
56  */
57
58 public class VisualizationTransformer {
59
60   private static final Logger LOG =
61       LoggerFactory.getInstance().getLogger(VisualizationTransformer.class);
62
63   List<JsonNode> flatNodeArray = new ArrayList<JsonNode>();
64
65   /*
66    * Maybe this isn't a string but Json-Model objects that we will convert to final string
67    * representation when we dump the node-array and link-array collections the post-data blob in the
68    * HttpServletResponse.
69    */
70
71   List<JsonNodeLink> linkArrayOutput = new ArrayList<JsonNodeLink>();
72
73
74
75   private VisualizationConfigs visualizationConfigs;
76
77
78   /**
79    * Instantiates a new visualization transformer.
80    *
81    * @throws Exception the exception
82    */
83   public VisualizationTransformer(VisualizationConfigs visualizationConfigs) throws Exception {
84     this.visualizationConfigs = visualizationConfigs;
85   }
86
87
88   /**
89    * Log optime.
90    *
91    * @param method the method
92    * @param startTimeInMs the start time in ms
93    */
94   private void logOptime(String method, long startTimeInMs) {
95     LOG.info(AaiUiMsgs.OPERATION_TIME, method,
96         String.valueOf((System.currentTimeMillis() - startTimeInMs)));
97   }
98
99   /**
100    * Adds the search target attributes to root node.
101    */
102   public void addSearchTargetAttributesToRootNode() {
103
104     for (JsonNode n : flatNodeArray) {
105       if (n.isRootNode()) {
106         n.getNodeMeta().setSearchTarget(true);
107         n.getNodeMeta().setClassName(this.visualizationConfigs.getSelectedSearchedNodeClassName());
108       }
109
110     }
111
112   }
113
114   /**
115    * Generate visualization output.
116    *
117    * @param preProcessingOpTimeInMs the pre processing op time in ms
118    * @param graphMeta the graph meta
119    * @return the d 3 visualization output
120    * @throws JsonProcessingException the json processing exception
121    * @throws IOException Signals that an I/O exception has occurred.
122    */
123
124   public D3VisualizationOutput generateVisualizationOutput(long preProcessingOpTimeInMs,
125       GraphMeta graphMeta) throws JsonProcessingException, IOException {
126
127     long opStartTimeInMs = System.currentTimeMillis();
128
129     /*
130      * iterate over the flat collection, and only add the graph nodes to the graph node collection
131      */
132
133     D3VisualizationOutput output = new D3VisualizationOutput();
134
135     output.setGraphMeta(graphMeta);
136
137     for (JsonNode n : flatNodeArray) {
138       if (n.getItemType() != null) {
139         output.pegCounter(n.getItemType());
140       }
141     }
142
143     output.addNodes(flatNodeArray);
144     output.addLinks(linkArrayOutput);
145
146     int numNodes = flatNodeArray.size();
147     int numLinks = linkArrayOutput.size();
148
149     LOG.info(AaiUiMsgs.VISUALIZATION_GRAPH_OUTPUT, String.valueOf(numNodes),
150         String.valueOf(numLinks));
151
152     if (numLinks < (numNodes - 1)) {
153       LOG.warn(AaiUiMsgs.DANGLING_NODE_WARNING, String.valueOf(numLinks), String.valueOf(numNodes));
154     }
155
156     ObjectMapper mapper = new ObjectMapper();
157
158     final String fileContent = ConfigHelper.getFileContents(
159         System.getProperty("AJSC_HOME") + this.visualizationConfigs.getAaiEntityNodeDescriptors());
160     com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDefinitions = mapper.readTree(fileContent);
161     graphMeta.setAaiEntityNodeDescriptors(aaiEntityNodeDefinitions);
162
163     graphMeta.setNumLinks(linkArrayOutput.size());
164     graphMeta.setNumNodes(flatNodeArray.size());
165     graphMeta.setRenderTimeInMs(preProcessingOpTimeInMs);
166
167     output.setGraphMeta(graphMeta);
168
169     logOptime("generateVisualizationOutput()", opStartTimeInMs);
170
171     return output;
172   }
173
174   /**
175    * Convert visualization output to json.
176    *
177    * @param output the output
178    * @return the string
179    * @throws JsonProcessingException the json processing exception
180    */
181   public String convertVisualizationOutputToJson(D3VisualizationOutput output)
182       throws JsonProcessingException {
183
184     if (output == null) {
185       return null;
186     }
187
188     ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
189
190     return ow.writeValueAsString(output);
191
192   }
193
194   /**
195    * Builds the links from graph collection.
196    *
197    * @param nodeMap the node map
198    */
199   public void buildLinksFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
200
201     for (ActiveInventoryNode ain : nodeMap.values()) {
202
203       /*
204        * This one is a little bit different, when we iterate over the collection we only want to
205        * draw the links for node that are less than the max traversal depth. We want to only draw
206        * links at a depth of n-1 because we are basing the links on the outbound neighbors from the
207        * current node.
208        */
209
210       if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
211
212         Collection<String> outboundNeighbors = ain.getOutboundNeighbors();
213
214         for (String outboundNeighbor : outboundNeighbors) {
215
216           JsonNodeLink nodeLink = new JsonNodeLink();
217
218           nodeLink.setId(UUID.randomUUID().toString());
219           nodeLink.setSource(ain.getNodeId());
220           nodeLink.setTarget(outboundNeighbor);
221
222           linkArrayOutput.add(nodeLink);
223
224         }
225
226         Collection<String> inboundNeighbors = ain.getInboundNeighbors();
227
228         for (String inboundNeighbor : inboundNeighbors) {
229
230           JsonNodeLink nodeLink = new JsonNodeLink();
231
232           nodeLink.setId(UUID.randomUUID().toString());
233           nodeLink.setSource(ain.getNodeId());
234           nodeLink.setTarget(inboundNeighbor);
235
236           linkArrayOutput.add(nodeLink);
237
238         }
239
240
241       } else {
242         if (LOG.isDebugEnabled()) {
243           LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "buildLinks()," + " Filtering node = "
244               + ain.getNodeId() + " @ depth = " + ain.getNodeDepth());
245         }
246
247       }
248     }
249
250   }
251
252   /**
253    * Builds the flat node array from graph collection.
254    *
255    * @param nodeMap the node map
256    */
257   /*
258    * Recursive function to walk multi-graph nodes and children to build a folded resource target
259    * graph.
260    */
261   public void buildFlatNodeArrayFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
262
263     for (ActiveInventoryNode n : nodeMap.values()) {
264
265       if (n.getNodeDepth() <= this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
266
267         JsonNode jsonNode = new JsonNode(n, this.visualizationConfigs);
268
269         jsonNode.getNodeMeta().setClassName(this.visualizationConfigs.getGeneralNodeClassName());
270
271         if (this.visualizationConfigs.isVisualizationDebugEnabled()) {
272
273           NodeDebug nodeDebug = jsonNode.getNodeMeta().getNodeDebug();
274
275           if (nodeDebug != null) {
276             nodeDebug.setProcessingError(n.isProcessingErrorOccurred());
277             nodeDebug.setProcessingErrorCauses(n.getProcessingErrorCauses());
278           }
279         }
280         flatNodeArray.add(jsonNode);
281       } else {
282         if (LOG.isDebugEnabled()) {
283           LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "Filtering node from visualization: " + n.getNodeId()
284               + " @ depth = " + n.getNodeDepth());
285         }
286       }
287     }
288   }
289
290 }