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