2  * ============LICENSE_START=======================================================
 
   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
 
  12  *       http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.aai.sparky.viewandinspect.services;
 
  24 import java.io.IOException;
 
  25 import java.util.ArrayList;
 
  26 import java.util.Collection;
 
  27 import java.util.List;
 
  29 import java.util.UUID;
 
  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;
 
  45 import com.fasterxml.jackson.core.JsonProcessingException;
 
  46 import com.fasterxml.jackson.databind.ObjectMapper;
 
  47 import com.fasterxml.jackson.databind.ObjectWriter;
 
  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.
 
  59 public class VisualizationTransformer {
 
  61   private static final Logger LOG = LoggerFactory.getInstance().getLogger(
 
  62       VisualizationTransformer.class);
 
  64   List<SparkyGraphNode> flatNodeArray = new ArrayList<SparkyGraphNode>();
 
  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.
 
  72   List<SparkyGraphLink> linkArrayOutput = new ArrayList<SparkyGraphLink>();
 
  74   private VisualizationConfigs visualizationConfigs;
 
  75   private SubscriptionConfig subConfig;
 
  78    * Instantiates a new visualization transformer.
 
  80    * @throws Exception the exception
 
  82   public VisualizationTransformer(VisualizationConfigs visualizationConfigs,
 
  83       SubscriptionConfig subConfig) throws Exception {
 
  84           this.visualizationConfigs = visualizationConfigs; 
 
  85           this.subConfig = subConfig;
 
  92    * @param method the method
 
  93    * @param startTimeInMs the start time in ms
 
  95   private void logOptime(String method, long startTimeInMs) {
 
  96     LOG.info(AaiUiMsgs.OPERATION_TIME, method,
 
  97         String.valueOf((System.currentTimeMillis() - startTimeInMs)));
 
 101    * Adds the search target attributes to root node.
 
 103   public void addSearchTargetAttributesToRootNode() {
 
 105     for (SparkyGraphNode n : flatNodeArray) {
 
 106       if (n.isRootNode()) {
 
 107         n.getNodeMeta().setSearchTarget(true);
 
 108         n.getNodeMeta().setClassName(this.visualizationConfigs.getSelectedSearchedNodeClassName());
 
 116    * Generate visualization output.
 
 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.
 
 125   public D3VisualizationOutput generateVisualizationOutput(long preProcessingOpTimeInMs,
 
 126       GraphMeta graphMeta) throws JsonProcessingException, IOException {
 
 128     long opStartTimeInMs = System.currentTimeMillis();
 
 131      * iterate over the flat collection, and only add the graph nodes to the graph node collection
 
 134     D3VisualizationOutput output = new D3VisualizationOutput();
 
 136     output.setGraphMeta(graphMeta);
 
 138     for (SparkyGraphNode n : flatNodeArray) {
 
 139       if ( n.getItemType()!= null) {
 
 140         output.pegCounter(n.getItemType());
 
 144     output.addNodes(flatNodeArray);
 
 145     output.addLinks(linkArrayOutput);
 
 147     int numNodes = flatNodeArray.size();
 
 148     int numLinks = linkArrayOutput.size();
 
 150     LOG.info(AaiUiMsgs.VISUALIZATION_GRAPH_OUTPUT, String.valueOf(numNodes),
 
 151         String.valueOf(numLinks));
 
 153     if (numLinks < (numNodes - 1)) {
 
 154       LOG.warn(AaiUiMsgs.DANGLING_NODE_WARNING, String.valueOf(numLinks),
 
 155           String.valueOf(numNodes));
 
 158     ObjectMapper mapper = new ObjectMapper();
 
 160     SparkyResourceLoader resourceLoader = visualizationConfigs.getResourceLoader();
 
 161     File aaiEntityDescriptorsFile = resourceLoader.getResourceAsFile(visualizationConfigs.getAaiEntityNodeDescriptors(), true);
 
 163     if (aaiEntityDescriptorsFile != null) {
 
 164       com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDefinitions =
 
 165           mapper.readTree(aaiEntityDescriptorsFile);
 
 166       graphMeta.setAaiEntityNodeDescriptors(aaiEntityNodeDefinitions);
 
 168       LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to find " + visualizationConfigs.getAaiEntityNodeDescriptors());
 
 169       graphMeta.setAaiEntityNodeDescriptors(null);
 
 172     graphMeta.setNumLinks(linkArrayOutput.size());
 
 173     graphMeta.setNumNodes(flatNodeArray.size());
 
 174     graphMeta.setRenderTimeInMs(preProcessingOpTimeInMs);
 
 176     output.setGraphMeta(graphMeta);
 
 178     logOptime("generateVisualizationOutput()", opStartTimeInMs);
 
 184    * Convert visualization output to json.
 
 186    * @param output the output
 
 188    * @throws JsonProcessingException the json processing exception
 
 190   public String convertVisualizationOutputToJson(D3VisualizationOutput output)
 
 191       throws JsonProcessingException {
 
 193     if (output == null) {
 
 197     ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
 
 199     return ow.writeValueAsString(output);
 
 204    * Builds the links from graph collection.
 
 206    * @param nodeMap the node map
 
 208   public void buildLinksFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
 
 210     for (ActiveInventoryNode ain : nodeMap.values()) {
 
 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
 
 219       if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
 
 221         Collection<String> outboundNeighbors = ain.getOutboundNeighbors();
 
 223         for (String outboundNeighbor : outboundNeighbors) {
 
 225           SparkyGraphLink nodeLink = new SparkyGraphLink();
 
 227           nodeLink.setId(UUID.randomUUID().toString());
 
 228           nodeLink.setSource(ain.getNodeId());
 
 229           nodeLink.setTarget(outboundNeighbor);
 
 231           linkArrayOutput.add(nodeLink);
 
 235         Collection<String> inboundNeighbors = ain.getInboundNeighbors();
 
 237         for (String inboundNeighbor : inboundNeighbors) {
 
 239           SparkyGraphLink nodeLink = new SparkyGraphLink();
 
 241           nodeLink.setId(UUID.randomUUID().toString());
 
 242           nodeLink.setSource(ain.getNodeId());
 
 243           nodeLink.setTarget(inboundNeighbor);
 
 245           linkArrayOutput.add(nodeLink);
 
 251         if (LOG.isDebugEnabled()) {
 
 252           LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "buildLinks(),"
 
 253               + " Filtering node = " + ain.getNodeId() + " @ depth = "
 
 254               + ain.getNodeDepth());
 
 263    * Builds the flat node array from graph collection.
 
 265    * @param nodeMap the node map
 
 268    * Recursive function to walk multi-graph nodes and children to build a folded resource target
 
 271   public void buildFlatNodeArrayFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
 
 273     for (ActiveInventoryNode n : nodeMap.values()) {
 
 275       if (n.getNodeDepth() <= this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
 
 277         SparkyGraphNode jsonNode = new SparkyGraphNode(n, this.visualizationConfigs, this.subConfig);
 
 279         jsonNode.getNodeMeta().setClassName(this.visualizationConfigs.getGeneralNodeClassName());
 
 281         if (this.visualizationConfigs.isVisualizationDebugEnabled()) {
 
 283           NodeDebug nodeDebug = jsonNode.getNodeMeta().getNodeDebug();
 
 285           if (nodeDebug != null) {
 
 286             nodeDebug.setProcessingError(n.isProcessingErrorOccurred());
 
 287             nodeDebug.setProcessingErrorCauses(n.getProcessingErrorCauses());
 
 290         flatNodeArray.add(jsonNode);
 
 292         if (LOG.isDebugEnabled()) {
 
 293           LOG.debug(AaiUiMsgs.DEBUG_GENERIC, 
 
 294               "Filtering node from visualization: " + n.getNodeId() + " @ depth = "