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;
25 import java.util.concurrent.ConcurrentHashMap;
27 import javax.servlet.ServletException;
29 import org.onap.aai.cl.api.Logger;
30 import org.onap.aai.cl.eelf.LoggerFactory;
31 import org.onap.aai.restclient.client.OperationResult;
32 import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
33 import org.onap.aai.sparky.logging.AaiUiMsgs;
34 import org.onap.aai.sparky.search.SearchServiceAdapter;
35 import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
36 import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
37 import org.onap.aai.sparky.sync.entity.SearchableEntity;
38 import org.onap.aai.sparky.util.NodeUtils;
39 import org.onap.aai.sparky.viewandinspect.VisualizationContext;
40 import org.onap.aai.sparky.viewandinspect.VisualizationContextBuilder;
41 import org.onap.aai.sparky.viewandinspect.VisualizationService;
42 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
43 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
44 import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
45 import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
46 import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
47 import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
49 import com.fasterxml.jackson.annotation.JsonInclude.Include;
50 import com.fasterxml.jackson.core.JsonProcessingException;
51 import com.fasterxml.jackson.databind.DeserializationFeature;
52 import com.fasterxml.jackson.databind.JsonNode;
53 import com.fasterxml.jackson.databind.ObjectMapper;
55 public class BaseVisualizationService implements VisualizationService {
57 private static final Logger LOG =
58 LoggerFactory.getInstance().getLogger(BaseVisualizationService.class);
60 protected ObjectMapper mapper = new ObjectMapper();
62 protected final SearchServiceAdapter searchServiceAdapter;
64 protected ConcurrentHashMap<Long, VisualizationContext> contextMap;
66 protected VisualizationConfigs visualizationConfigs;
67 protected SubscriptionConfig subConfig;
68 protected RestEndpointConfig endpointConfig;
69 protected ElasticSearchSchemaConfig schemaEConfig;
71 protected VisualizationContextBuilder contextBuilder;
73 public BaseVisualizationService(VisualizationContextBuilder contextBuilder,
74 VisualizationConfigs visualizationConfigs, SearchServiceAdapter searchServiceAdapter,
75 RestEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig,
76 SubscriptionConfig subscriptionConfig) throws Exception {
78 this.visualizationConfigs = visualizationConfigs;
79 this.endpointConfig = endpointConfig;
80 this.schemaEConfig = schemaConfig;
81 this.subConfig = subscriptionConfig;
82 this.contextBuilder = contextBuilder;
84 this.searchServiceAdapter = searchServiceAdapter;
86 this.mapper = new ObjectMapper();
87 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
89 this.contextMap = new ConcurrentHashMap<Long, VisualizationContext>();
94 * Analyze query request body.
96 * @param queryRequestJson the query request json
97 * @return the query request
100 public QueryRequest analyzeQueryRequestBody(String queryRequestJson) {
103 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
104 "analyzeQueryRequestBody()," + " queryRequestJson = " + queryRequestJson);
106 ObjectMapper nonEmptyMapper = new ObjectMapper();
107 nonEmptyMapper.setSerializationInclusion(Include.NON_EMPTY);
109 QueryRequest queryBody = null;
112 queryBody = nonEmptyMapper.readValue(queryRequestJson, QueryRequest.class);
113 } catch (Exception exc) {
114 LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT, "Analyzing query request body.",
115 exc.getLocalizedMessage());
125 * @param method the method
126 * @param opStartTimeInMs the op start time in ms
128 protected void logOptime(String method, long opStartTimeInMs) {
129 LOG.info(AaiUiMsgs.OPERATION_TIME, method,
130 String.valueOf(System.currentTimeMillis() - opStartTimeInMs));
133 protected SearchableEntity extractSearchableEntityFromElasticEntity(OperationResult operationResult) {
134 if (operationResult == null || !operationResult.wasSuccessful()) {
135 // error, return empty collection
139 SearchableEntity sourceEntity = null;
140 if (operationResult.wasSuccessful()) {
143 JsonNode searchServiceResults = mapper.readValue(operationResult.getResult(), JsonNode.class);
145 if (searchServiceResults != null) {
146 JsonNode sourceField = extractSearchServiceContent(searchServiceResults);
148 if (sourceField != null) {
149 sourceEntity = new SearchableEntity();
151 String entityType = NodeUtils.extractFieldValueFromObject(sourceField, "entityType");
152 sourceEntity.setEntityType(entityType);
153 String entityPrimaryKeyValue = NodeUtils.extractFieldValueFromObject(sourceField, "entityPrimaryKeyValue");
154 sourceEntity.setEntityPrimaryKeyValue(entityPrimaryKeyValue);
155 String link = NodeUtils.extractFieldValueFromObject(sourceField, "link");
156 sourceEntity.setLink(link);
157 String lastmodTimestamp = NodeUtils.extractFieldValueFromObject(sourceField, "lastmodTimestamp");
158 sourceEntity.setEntityTimeStamp(lastmodTimestamp);
161 } catch (IOException ioe) {
162 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "a json node ", ioe.getLocalizedMessage());
169 * Builds the visualization using generic query.
171 * @param queryRequest the query request
172 * @return the operation result
175 public OperationResult buildVisualization(QueryRequest queryRequest) {
177 OperationResult returnValue = new OperationResult();
178 OperationResult dataCollectionResult;
179 QueryParams queryParams = null;
180 SearchableEntity sourceEntity = null;
185 * Here is where we need to make a dip to elastic-search for the self-link by entity-id (link
188 dataCollectionResult = searchServiceAdapter.retrieveEntityById(queryRequest.getHashId(),
189 schemaEConfig.getIndexName());
191 sourceEntity = extractSearchableEntityFromElasticEntity(dataCollectionResult);
193 if (sourceEntity != null) {
194 sourceEntity.generateId();
197 queryParams = new QueryParams();
198 queryParams.setSearchTargetNodeId(queryRequest.getHashId());
200 } catch (Exception e1) {
201 LOG.error(AaiUiMsgs.FAILED_TO_GET_NODES_QUERY_RESULT, e1.getLocalizedMessage());
202 dataCollectionResult = new OperationResult(500, "Failed to get nodes-query result from AAI");
205 if (dataCollectionResult == null || dataCollectionResult.getResultCode() == 200) {
207 String d3OutputJsonOutput = null;
211 d3OutputJsonOutput = getVisualizationOutputBasedonGenericQuery( sourceEntity, queryParams, queryRequest);
213 if (LOG.isDebugEnabled()) {
214 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
215 "Generated D3" + " output as json = " + d3OutputJsonOutput);
218 if (d3OutputJsonOutput != null) {
219 returnValue.setResultCode(200);
220 returnValue.setResult(d3OutputJsonOutput);
222 returnValue.setResult(500, "Failed to generate D3 graph visualization");
225 } catch (Exception exc) {
226 returnValue.setResult(500,
227 "Failed to generate D3 graph visualization, due to a servlet exception.");
228 LOG.error(AaiUiMsgs.ERROR_D3_GRAPH_VISUALIZATION, exc.getLocalizedMessage());
231 returnValue.setResult(dataCollectionResult.getResultCode(), dataCollectionResult.getResult());
240 * Gets the visualization output basedon generic query.
242 * @param searchtargetEntity entity that will be used to start visualization flow
243 * @param queryParams the query params
244 * @return the visualization output basedon generic query
245 * @throws ServletException the servlet exception
248 protected String getVisualizationOutputBasedonGenericQuery(SearchableEntity searchtargetEntity,
249 QueryParams queryParams, QueryRequest request) throws ServletException {
251 long opStartTimeInMs = System.currentTimeMillis();
253 VisualizationTransformer transformer = null;
255 transformer = new VisualizationTransformer(visualizationConfigs, subConfig);
256 } catch (Exception exc) {
257 throw new ServletException(
258 "Failed to create VisualizationTransformer instance because of execption", exc);
261 VisualizationContext visContext = null;
265 visContext = contextBuilder.getVisualizationContext();
266 contextMap.putIfAbsent(visContext.getContextId(), visContext);
268 } catch (Exception e1) {
269 LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT,
270 "While building Visualization Context, " + e1.getLocalizedMessage());
271 throw new ServletException(e1);
274 long startTimeInMs = System.currentTimeMillis();
276 visContext.processSelfLinks(searchtargetEntity, queryParams);
277 contextMap.remove(visContext.getContextId());
279 logOptime("collectSelfLinkNodes()", startTimeInMs);
282 * Flatten the graphs into a set of Graph and Link nodes. In this method I want the node graph
283 * resulting from the edge-tag-query to be represented first, and then we'll layer in
286 long overlayDataStartTimeInMs = System.currentTimeMillis();
288 Map<String, ActiveInventoryNode> cachedNodeMap = visContext.getNodeCache();
290 if (LOG.isDebugEnabled()) {
292 StringBuilder sb = new StringBuilder(128);
294 sb.append("\nCached Node Map:\n");
295 for (String k : cachedNodeMap.keySet()) {
297 sb.append("\n").append(cachedNodeMap.get(k).dumpNodeTree(true));
300 LOG.debug(AaiUiMsgs.DEBUG_GENERIC, sb.toString());
303 GraphMeta graphMeta = new GraphMeta();
305 transformer.buildFlatNodeArrayFromGraphCollection(cachedNodeMap, graphMeta);
306 transformer.buildLinksFromGraphCollection(cachedNodeMap);
309 * - Apply configuration-driven styling
310 * - Build the final transformation response object
311 * - Use information we have to populate the GraphMeta object
314 transformer.addSearchTargetAttributesToRootNode();
316 D3VisualizationOutput output = getD3VisualizationOutput(opStartTimeInMs, transformer, graphMeta);
318 String jsonResponse = null;
320 if (output != null) {
323 jsonResponse = transformer.convertVisualizationOutputToJson(output);
324 } catch (JsonProcessingException jpe) {
325 throw new ServletException(
326 "Caught an exception while converting visualization output to json", jpe);
330 logOptime("[build flat node array, add relationship data, search target,"
331 + " color scheme, and generate visualization output]", overlayDataStartTimeInMs);
333 logOptime("doFilter()", opStartTimeInMs);
339 protected D3VisualizationOutput getD3VisualizationOutput(long opStartTimeInMs,
340 VisualizationTransformer transformer, GraphMeta graphMeta) throws ServletException {
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());
353 protected JsonNode extractSearchServiceContent(JsonNode returnedData){
355 JsonNode searchResults = returnedData.get("searchResult");
356 JsonNode searchHits = searchResults.get("hits");
357 JsonNode searchDoc = searchHits.get(0).get("document");
358 JsonNode content = searchDoc.get("content");
364 public void shutdown() {
365 if ( contextBuilder != null ) {
366 contextBuilder.shutdown();