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();