2 * ============LICENSE_START===================================================
3 * SPARKY (AAI UI service)
4 * ============================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=====================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.onap.aai.sparky.viewandinspect.services;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
33 import java.util.UUID;
35 import org.onap.aai.cl.api.Logger;
36 import org.onap.aai.cl.eelf.LoggerFactory;
37 import org.onap.aai.sparky.config.SparkyResourceLoader;
38 import org.onap.aai.sparky.logging.AaiUiMsgs;
39 import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
40 import org.onap.aai.sparky.util.ConfigHelper;
41 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
42 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
43 import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
44 import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
45 import org.onap.aai.sparky.viewandinspect.entity.NodeDebug;
46 import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphLink;
47 import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphNode;
49 import com.fasterxml.jackson.core.JsonProcessingException;
50 import com.fasterxml.jackson.databind.ObjectMapper;
51 import com.fasterxml.jackson.databind.ObjectWriter;
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.
63 public class VisualizationTransformer {
65 private static final Logger LOG = LoggerFactory.getInstance().getLogger(
66 VisualizationTransformer.class);
68 List<SparkyGraphNode> flatNodeArray = new ArrayList<SparkyGraphNode>();
71 * Maybe this isn't a string but Json-Model objects that we will convert to final string
72 * representation when we dump the node-array and link-array collections the post-data blob in the
73 * HttpServletResponse.
76 List<SparkyGraphLink> linkArrayOutput = new ArrayList<SparkyGraphLink>();
78 private VisualizationConfigs visualizationConfigs;
79 private SubscriptionConfig subConfig;
82 * Instantiates a new visualization transformer.
84 * @throws Exception the exception
86 public VisualizationTransformer(VisualizationConfigs visualizationConfigs,
87 SubscriptionConfig subConfig) throws Exception {
88 this.visualizationConfigs = visualizationConfigs;
89 this.subConfig = subConfig;
96 * @param method the method
97 * @param startTimeInMs the start time in ms
99 private void logOptime(String method, long startTimeInMs) {
100 LOG.info(AaiUiMsgs.OPERATION_TIME, method,
101 String.valueOf((System.currentTimeMillis() - startTimeInMs)));
105 * Adds the search target attributes to root node.
107 public void addSearchTargetAttributesToRootNode() {
109 for (SparkyGraphNode n : flatNodeArray) {
110 if (n.isRootNode()) {
111 n.getNodeMeta().setSearchTarget(true);
112 n.getNodeMeta().setClassName(this.visualizationConfigs.getSelectedSearchedNodeClassName());
120 * Generate visualization output.
122 * @param preProcessingOpTimeInMs the pre processing op time in ms
123 * @param graphMeta the graph meta
124 * @return the d 3 visualization output
125 * @throws JsonProcessingException the json processing exception
126 * @throws IOException Signals that an I/O exception has occurred.
129 public D3VisualizationOutput generateVisualizationOutput(long preProcessingOpTimeInMs,
130 GraphMeta graphMeta) throws JsonProcessingException, IOException {
132 long opStartTimeInMs = System.currentTimeMillis();
135 * iterate over the flat collection, and only add the graph nodes to the graph node collection
138 D3VisualizationOutput output = new D3VisualizationOutput();
140 output.setGraphMeta(graphMeta);
142 for (SparkyGraphNode n : flatNodeArray) {
143 if ( n.getItemType()!= null) {
144 output.pegCounter(n.getItemType());
148 output.addNodes(flatNodeArray);
149 output.addLinks(linkArrayOutput);
151 int numNodes = flatNodeArray.size();
152 int numLinks = linkArrayOutput.size();
154 LOG.info(AaiUiMsgs.VISUALIZATION_GRAPH_OUTPUT, String.valueOf(numNodes),
155 String.valueOf(numLinks));
157 if (numLinks < (numNodes - 1)) {
158 LOG.warn(AaiUiMsgs.DANGLING_NODE_WARNING, String.valueOf(numLinks),
159 String.valueOf(numNodes));
162 ObjectMapper mapper = new ObjectMapper();
164 SparkyResourceLoader resourceLoader = visualizationConfigs.getResourceLoader();
165 File aaiEntityDescriptorsFile = resourceLoader.getResourceAsFile(visualizationConfigs.getAaiEntityNodeDescriptors(), true);
167 if (aaiEntityDescriptorsFile != null) {
168 com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDefinitions =
169 mapper.readTree(aaiEntityDescriptorsFile);
170 graphMeta.setAaiEntityNodeDescriptors(aaiEntityNodeDefinitions);
172 LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to find " + visualizationConfigs.getAaiEntityNodeDescriptors());
173 graphMeta.setAaiEntityNodeDescriptors(null);
176 graphMeta.setNumLinks(linkArrayOutput.size());
177 graphMeta.setNumNodes(flatNodeArray.size());
178 graphMeta.setRenderTimeInMs(preProcessingOpTimeInMs);
180 output.setGraphMeta(graphMeta);
182 logOptime("generateVisualizationOutput()", opStartTimeInMs);
188 * Convert visualization output to json.
190 * @param output the output
192 * @throws JsonProcessingException the json processing exception
194 public String convertVisualizationOutputToJson(D3VisualizationOutput output)
195 throws JsonProcessingException {
197 if (output == null) {
201 ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
203 return ow.writeValueAsString(output);
208 * Builds the links from graph collection.
210 * @param nodeMap the node map
212 public void buildLinksFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
214 for (ActiveInventoryNode ain : nodeMap.values()) {
217 * This one is a little bit different, when we iterate over the collection we only want to
218 * draw the links for node that are less than the max traversal depth. We want to only draw
219 * links at a depth of n-1 because we are basing the links on the outbound neighbors from the
223 if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
225 Collection<String> outboundNeighbors = ain.getOutboundNeighbors();
227 for (String outboundNeighbor : outboundNeighbors) {
229 SparkyGraphLink nodeLink = new SparkyGraphLink();
231 nodeLink.setId(UUID.randomUUID().toString());
232 nodeLink.setSource(ain.getNodeId());
233 nodeLink.setTarget(outboundNeighbor);
235 linkArrayOutput.add(nodeLink);
239 Collection<String> inboundNeighbors = ain.getInboundNeighbors();
241 for (String inboundNeighbor : inboundNeighbors) {
243 SparkyGraphLink nodeLink = new SparkyGraphLink();
245 nodeLink.setId(UUID.randomUUID().toString());
246 nodeLink.setSource(ain.getNodeId());
247 nodeLink.setTarget(inboundNeighbor);
249 linkArrayOutput.add(nodeLink);
255 if (LOG.isDebugEnabled()) {
256 LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "buildLinks(),"
257 + " Filtering node = " + ain.getNodeId() + " @ depth = "
258 + ain.getNodeDepth());
267 * Builds the flat node array from graph collection.
269 * @param nodeMap the node map
272 * Recursive function to walk multi-graph nodes and children to build a folded resource target
275 public void buildFlatNodeArrayFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
277 for (ActiveInventoryNode n : nodeMap.values()) {
279 if (n.getNodeDepth() <= this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
281 SparkyGraphNode jsonNode = new SparkyGraphNode(n, this.visualizationConfigs, this.subConfig);
283 jsonNode.getNodeMeta().setClassName(this.visualizationConfigs.getGeneralNodeClassName());
285 if (this.visualizationConfigs.isVisualizationDebugEnabled()) {
287 NodeDebug nodeDebug = jsonNode.getNodeMeta().getNodeDebug();
289 if (nodeDebug != null) {
290 nodeDebug.setProcessingError(n.isProcessingErrorOccurred());
291 nodeDebug.setProcessingErrorCauses(n.getProcessingErrorCauses());
294 flatNodeArray.add(jsonNode);
296 if (LOG.isDebugEnabled()) {
297 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
298 "Filtering node from visualization: " + n.getNodeId() + " @ depth = "