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