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;
 
  23 import java.io.IOException;
 
  24 import java.security.SecureRandom;
 
  26 import java.util.concurrent.ConcurrentHashMap;
 
  27 import java.util.concurrent.ExecutorService;
 
  29 import javax.servlet.ServletException;
 
  31 import org.onap.aai.cl.api.Logger;
 
  32 import org.onap.aai.cl.eelf.LoggerFactory;
 
  33 import org.onap.aai.restclient.client.OperationResult;
 
  34 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
 
  35 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
 
  36 import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
 
  37 import org.onap.aai.sparky.dal.ElasticSearchAdapter;
 
  38 import org.onap.aai.sparky.dal.GizmoAdapter;
 
  39 import org.onap.aai.sparky.logging.AaiUiMsgs;
 
  40 import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
 
  41 import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
 
  42 import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
 
  43 import org.onap.aai.sparky.sync.entity.SearchableEntity;
 
  44 import org.onap.aai.sparky.util.NodeUtils;
 
  45 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
 
  46 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
 
  47 import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
 
  48 import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
 
  49 import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
 
  50 import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
 
  52 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 
  53 import com.fasterxml.jackson.core.JsonProcessingException;
 
  54 import com.fasterxml.jackson.databind.DeserializationFeature;
 
  55 import com.fasterxml.jackson.databind.JsonNode;
 
  56 import com.fasterxml.jackson.databind.ObjectMapper;
 
  58 public class BaseVisualizationService implements VisualizationService {
 
  60   private static final Logger LOG =
 
  61       LoggerFactory.getInstance().getLogger(BaseVisualizationService.class);
 
  63   private ObjectMapper mapper = new ObjectMapper();
 
  65   private final ActiveInventoryAdapter aaiAdapter;
 
  66   private final GizmoAdapter gizmoAdapter;
 
  67   private final ElasticSearchAdapter esAdapter;
 
  68   private final ExecutorService aaiExecutorService;
 
  70   private ConcurrentHashMap<Long, VisualizationContext> contextMap;
 
  71   private final SecureRandom secureRandom;
 
  73   private VisualizationConfigs visualizationConfigs;
 
  74   private SubscriptionConfig subConfig;
 
  75   private ElasticSearchEndpointConfig endpointEConfig;
 
  76   private ElasticSearchSchemaConfig schemaEConfig;
 
  77   private OxmEntityLookup oxmEntityLookup;
 
  79         public BaseVisualizationService(OxmModelLoader loader, VisualizationConfigs visualizationConfigs,
 
  80                         ActiveInventoryAdapter aaiAdapter, GizmoAdapter gizmoAdapter, ElasticSearchAdapter esAdapter,
 
  81                         ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig,
 
  82                         int numActiveInventoryWorkers, OxmEntityLookup oxmEntityLookup, SubscriptionConfig subscriptionConfig)
 
  85     this.visualizationConfigs = visualizationConfigs;
 
  86     this.endpointEConfig = endpointConfig; 
 
  87     this.schemaEConfig = schemaConfig; 
 
  88     this.oxmEntityLookup = oxmEntityLookup;
 
  89     this.subConfig = subscriptionConfig;
 
  92     secureRandom = new SecureRandom();
 
  95      * Fix constructor with properly wired in properties
 
  98     this.aaiAdapter = aaiAdapter;
 
  99     this.gizmoAdapter = gizmoAdapter;
 
 100     this.esAdapter = esAdapter; 
 
 102     this.mapper = new ObjectMapper();
 
 103     mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 
 105     this.contextMap = new ConcurrentHashMap<Long, VisualizationContext>();
 
 107     this.aaiExecutorService = NodeUtils.createNamedExecutor("SLNC-WORKER",
 
 108         numActiveInventoryWorkers, LOG);
 
 113    * Analyze query request body.
 
 115    * @param queryRequestJson the query request json
 
 116    * @return the query request
 
 119   public QueryRequest analyzeQueryRequestBody(String queryRequestJson) {
 
 122     LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
 
 123         "analyzeQueryRequestBody()," + " queryRequestJson = " + queryRequestJson);
 
 125     ObjectMapper nonEmptyMapper = new ObjectMapper();
 
 126     nonEmptyMapper.setSerializationInclusion(Include.NON_EMPTY);
 
 128     QueryRequest queryBody = null;
 
 131       queryBody = nonEmptyMapper.readValue(queryRequestJson, QueryRequest.class);
 
 132     } catch (Exception exc) {
 
 133       LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT, "Analyzing query request body.",
 
 134           exc.getLocalizedMessage());
 
 144    * @param method the method
 
 145    * @param opStartTimeInMs the op start time in ms
 
 147   private void logOptime(String method, long opStartTimeInMs) {
 
 148     LOG.info(AaiUiMsgs.OPERATION_TIME, method,
 
 149         String.valueOf(System.currentTimeMillis() - opStartTimeInMs));
 
 152   private SearchableEntity extractSearchableEntityFromElasticEntity(OperationResult operationResult) {
 
 153     if (operationResult == null || !operationResult.wasSuccessful()) {
 
 154       // error, return empty collection
 
 158     SearchableEntity sourceEntity = null;
 
 159     if (operationResult.wasSuccessful()) {
 
 162         JsonNode elasticValue = mapper.readValue(operationResult.getResult(), JsonNode.class);
 
 164         if (elasticValue != null) {
 
 165           JsonNode sourceField = elasticValue.get("_source");
 
 167           if (sourceField != null) {
 
 168             sourceEntity = new SearchableEntity();
 
 170             String entityType = NodeUtils.extractFieldValueFromObject(sourceField, "entityType"); 
 
 171             sourceEntity.setEntityType(entityType);  
 
 172             String entityPrimaryKeyValue = NodeUtils.extractFieldValueFromObject(sourceField, "entityPrimaryKeyValue");
 
 173             sourceEntity.setEntityPrimaryKeyValue(entityPrimaryKeyValue);
 
 174             String link = NodeUtils.extractFieldValueFromObject(sourceField, "link"); 
 
 175             sourceEntity.setLink(link);
 
 176             String lastmodTimestamp = NodeUtils.extractFieldValueFromObject(sourceField, "lastmodTimestamp");
 
 177             sourceEntity.setEntityTimeStamp(lastmodTimestamp);
 
 180       } catch (IOException ioe) {
 
 181         LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "a json node ", ioe.getLocalizedMessage());
 
 188    * Builds the visualization using generic query.
 
 190    * @param queryRequest the query request
 
 191    * @return the operation result
 
 193   public OperationResult buildVisualizationUsingGenericQuery(QueryRequest queryRequest) {
 
 195     OperationResult returnValue = new OperationResult();
 
 196     OperationResult dataCollectionResult = new OperationResult();
 
 197     QueryParams queryParams = null;
 
 198     SearchableEntity sourceEntity = null;
 
 203        * Here is where we need to make a dip to elastic-search for the self-link by entity-id (link
 
 206       dataCollectionResult = esAdapter.retrieveEntityById(endpointEConfig.getEsIpAddress(), 
 
 207                   endpointEConfig.getEsServerPort(),schemaEConfig.getIndexName(),
 
 208                   schemaEConfig.getIndexDocType(), queryRequest.getHashId());
 
 209       sourceEntity = extractSearchableEntityFromElasticEntity(dataCollectionResult);
 
 211       if (sourceEntity != null) {
 
 212         sourceEntity.generateId();
 
 215       queryParams = new QueryParams();
 
 216       queryParams.setSearchTargetNodeId(queryRequest.getHashId());
 
 218     } catch (Exception e1) {
 
 219       LOG.error(AaiUiMsgs.FAILED_TO_GET_NODES_QUERY_RESULT, e1.getLocalizedMessage());
 
 220       dataCollectionResult = new OperationResult(500, "Failed to get nodes-query result from AAI");
 
 223     if (dataCollectionResult.getResultCode() == 200) {
 
 225       String d3OutputJsonOutput = null;
 
 229         d3OutputJsonOutput = getVisualizationOutputBasedonGenericQuery( sourceEntity, queryParams, queryRequest);
 
 231         if (LOG.isDebugEnabled()) {
 
 232           LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
 
 233               "Generated D3" + " output as json = " + d3OutputJsonOutput);
 
 236         if (d3OutputJsonOutput != null) {
 
 237           returnValue.setResultCode(200);
 
 238           returnValue.setResult(d3OutputJsonOutput);
 
 240           returnValue.setResult(500, "Failed to generate D3 graph visualization");
 
 243       } catch (Exception exc) {
 
 244         returnValue.setResult(500,
 
 245             "Failed to generate D3 graph visualization, due to a servlet exception.");
 
 246         LOG.error(AaiUiMsgs.ERROR_D3_GRAPH_VISUALIZATION, exc.getLocalizedMessage());
 
 249       returnValue.setResult(dataCollectionResult.getResultCode(), dataCollectionResult.getResult());
 
 258    * Gets the visualization output basedon generic query.
 
 260    * @param searchtargetEntity entity that will be used to start visualization flow
 
 261    * @param queryParams the query params
 
 262    * @return the visualization output basedon generic query
 
 263    * @throws ServletException the servlet exception
 
 266   private String getVisualizationOutputBasedonGenericQuery(SearchableEntity searchtargetEntity,
 
 267       QueryParams queryParams, QueryRequest request) throws ServletException {
 
 269     long opStartTimeInMs = System.currentTimeMillis();
 
 271     VisualizationTransformer transformer = null;
 
 273       transformer = new VisualizationTransformer(visualizationConfigs, subConfig);
 
 274     } catch (Exception exc) {
 
 275       throw new ServletException(
 
 276           "Failed to create VisualizationTransformer instance because of execption", exc);
 
 279     VisualizationContext visContext = null;
 
 280     long contextId = secureRandom.nextLong();
 
 282         if ( visualizationConfigs.isGizmoEnabled()) {
 
 283               visContext = new BaseGizmoVisualizationContext(contextId, this.gizmoAdapter, aaiExecutorService,
 
 284                       this.visualizationConfigs, oxmEntityLookup);
 
 286               visContext = new BaseVisualizationContext(contextId, this.aaiAdapter, aaiExecutorService,
 
 287                       this.visualizationConfigs, oxmEntityLookup);
 
 290       contextMap.putIfAbsent(contextId, visContext);
 
 291     } catch (Exception e1) {
 
 292       LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT,
 
 293           "While building Visualization Context, " + e1.getLocalizedMessage());
 
 294       throw new ServletException(e1);
 
 297     String jsonResponse = null;
 
 299     long startTimeInMs = System.currentTimeMillis();
 
 301     visContext.processSelfLinks(searchtargetEntity, queryParams);
 
 302     contextMap.remove(contextId);
 
 304     logOptime("collectSelfLinkNodes()", startTimeInMs);
 
 307      * Flatten the graphs into a set of Graph and Link nodes. In this method I want the node graph
 
 308      * resulting from the edge-tag-query to be represented first, and then we'll layer in
 
 311     long overlayDataStartTimeInMs = System.currentTimeMillis();
 
 313     Map<String, ActiveInventoryNode> cachedNodeMap = visContext.getNodeCache();
 
 315     if (LOG.isDebugEnabled()) {
 
 317       StringBuilder sb = new StringBuilder(128);
 
 319       sb.append("\nCached Node Map:\n");
 
 320       for (String k : cachedNodeMap.keySet()) {
 
 322         sb.append("\n").append(cachedNodeMap.get(k).dumpNodeTree(true));
 
 325       LOG.debug(AaiUiMsgs.DEBUG_GENERIC, sb.toString());
 
 328     transformer.buildFlatNodeArrayFromGraphCollection(cachedNodeMap);
 
 329     transformer.buildLinksFromGraphCollection(cachedNodeMap);
 
 332      * - Apply configuration-driven styling
 
 333      * - Build the final transformation response object
 
 334      * - Use information we have to populate the GraphMeta object
 
 337     transformer.addSearchTargetAttributesToRootNode();
 
 339     GraphMeta graphMeta = new GraphMeta();
 
 341     D3VisualizationOutput output = null;
 
 344           .generateVisualizationOutput((System.currentTimeMillis() - opStartTimeInMs), graphMeta);
 
 345     } catch (JsonProcessingException exc) {
 
 346       throw new ServletException("Caught an exception while generation visualization output", exc);
 
 347     } catch (IOException exc) {
 
 348       LOG.error(AaiUiMsgs.FAILURE_TO_PROCESS_REQUEST, exc.getLocalizedMessage());
 
 351     output.setInlineMessage(visContext.getInlineMessage());
 
 352     output.getGraphMeta().setNumLinkResolveFailed(visContext.getNumFailedLinkResolve());
 
 353     output.getGraphMeta().setNumLinksResolvedSuccessfullyFromCache(
 
 354         visContext.getNumSuccessfulLinkResolveFromCache());
 
 355     output.getGraphMeta().setNumLinksResolvedSuccessfullyFromServer(
 
 356         visContext.getNumSuccessfulLinkResolveFromFromServer());
 
 359       jsonResponse = transformer.convertVisualizationOutputToJson(output);
 
 360     } catch (JsonProcessingException jpe) {
 
 361       throw new ServletException(
 
 362           "Caught an exception while converting visualization output to json", jpe);
 
 365     logOptime("[build flat node array, add relationship data, search target,"
 
 366         + " color scheme, and generate visualization output]", overlayDataStartTimeInMs);
 
 368     logOptime("doFilter()", opStartTimeInMs);
 
 374   public void shutdown() {
 
 375     aaiExecutorService.shutdown();