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