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;
27 import java.io.IOException;
28 import java.security.SecureRandom;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ExecutorService;
33 import javax.servlet.ServletException;
35 import org.onap.aai.cl.api.Logger;
36 import org.onap.aai.cl.eelf.LoggerFactory;
37 import org.onap.aai.restclient.client.OperationResult;
38 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
39 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
40 import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
41 import org.onap.aai.sparky.dal.ElasticSearchAdapter;
42 import org.onap.aai.sparky.dal.GizmoAdapter;
43 import org.onap.aai.sparky.logging.AaiUiMsgs;
44 import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
45 import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
46 import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
47 import org.onap.aai.sparky.sync.entity.SearchableEntity;
48 import org.onap.aai.sparky.util.NodeUtils;
49 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
50 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
51 import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
52 import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
53 import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
54 import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
56 import com.fasterxml.jackson.annotation.JsonInclude.Include;
57 import com.fasterxml.jackson.core.JsonProcessingException;
58 import com.fasterxml.jackson.databind.DeserializationFeature;
59 import com.fasterxml.jackson.databind.JsonNode;
60 import com.fasterxml.jackson.databind.ObjectMapper;
62 public class BaseVisualizationService implements VisualizationService {
64 private static final Logger LOG =
65 LoggerFactory.getInstance().getLogger(BaseVisualizationService.class);
67 private ObjectMapper mapper = new ObjectMapper();
69 private final ActiveInventoryAdapter aaiAdapter;
70 private final GizmoAdapter gizmoAdapter;
71 private final ElasticSearchAdapter esAdapter;
72 private final ExecutorService aaiExecutorService;
74 private ConcurrentHashMap<Long, VisualizationContext> contextMap;
75 private final SecureRandom secureRandom;
77 private VisualizationConfigs visualizationConfigs;
78 private SubscriptionConfig subConfig;
79 private ElasticSearchEndpointConfig endpointEConfig;
80 private ElasticSearchSchemaConfig schemaEConfig;
81 private OxmEntityLookup oxmEntityLookup;
83 public BaseVisualizationService(OxmModelLoader loader, VisualizationConfigs visualizationConfigs,
84 ActiveInventoryAdapter aaiAdapter, GizmoAdapter gizmoAdapter, ElasticSearchAdapter esAdapter,
85 ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig,
86 int numActiveInventoryWorkers, OxmEntityLookup oxmEntityLookup, SubscriptionConfig subscriptionConfig)
89 this.visualizationConfigs = visualizationConfigs;
90 this.endpointEConfig = endpointConfig;
91 this.schemaEConfig = schemaConfig;
92 this.oxmEntityLookup = oxmEntityLookup;
93 this.subConfig = subscriptionConfig;
96 secureRandom = new SecureRandom();
99 * Fix constructor with properly wired in properties
102 this.aaiAdapter = aaiAdapter;
103 this.gizmoAdapter = gizmoAdapter;
104 this.esAdapter = esAdapter;
106 this.mapper = new ObjectMapper();
107 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
109 this.contextMap = new ConcurrentHashMap<Long, VisualizationContext>();
111 this.aaiExecutorService = NodeUtils.createNamedExecutor("SLNC-WORKER",
112 numActiveInventoryWorkers, LOG);
117 * Analyze query request body.
119 * @param queryRequestJson the query request json
120 * @return the query request
123 public QueryRequest analyzeQueryRequestBody(String queryRequestJson) {
126 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
127 "analyzeQueryRequestBody()," + " queryRequestJson = " + queryRequestJson);
129 ObjectMapper nonEmptyMapper = new ObjectMapper();
130 nonEmptyMapper.setSerializationInclusion(Include.NON_EMPTY);
132 QueryRequest queryBody = null;
135 queryBody = nonEmptyMapper.readValue(queryRequestJson, QueryRequest.class);
136 } catch (Exception exc) {
137 LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT, "Analyzing query request body.",
138 exc.getLocalizedMessage());
148 * @param method the method
149 * @param opStartTimeInMs the op start time in ms
151 private void logOptime(String method, long opStartTimeInMs) {
152 LOG.info(AaiUiMsgs.OPERATION_TIME, method,
153 String.valueOf(System.currentTimeMillis() - opStartTimeInMs));
156 private SearchableEntity extractSearchableEntityFromElasticEntity(OperationResult operationResult) {
157 if (operationResult == null || !operationResult.wasSuccessful()) {
158 // error, return empty collection
162 SearchableEntity sourceEntity = null;
163 if (operationResult.wasSuccessful()) {
166 JsonNode elasticValue = mapper.readValue(operationResult.getResult(), JsonNode.class);
168 if (elasticValue != null) {
169 JsonNode sourceField = elasticValue.get("_source");
171 if (sourceField != null) {
172 sourceEntity = new SearchableEntity();
174 String entityType = NodeUtils.extractFieldValueFromObject(sourceField, "entityType");
175 sourceEntity.setEntityType(entityType);
176 String entityPrimaryKeyValue = NodeUtils.extractFieldValueFromObject(sourceField, "entityPrimaryKeyValue");
177 sourceEntity.setEntityPrimaryKeyValue(entityPrimaryKeyValue);
178 String link = NodeUtils.extractFieldValueFromObject(sourceField, "link");
179 sourceEntity.setLink(link);
180 String lastmodTimestamp = NodeUtils.extractFieldValueFromObject(sourceField, "lastmodTimestamp");
181 sourceEntity.setEntityTimeStamp(lastmodTimestamp);
184 } catch (IOException ioe) {
185 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "a json node ", ioe.getLocalizedMessage());
192 * Builds the visualization using generic query.
194 * @param queryRequest the query request
195 * @return the operation result
197 public OperationResult buildVisualizationUsingGenericQuery(QueryRequest queryRequest) {
199 OperationResult returnValue = new OperationResult();
200 OperationResult dataCollectionResult = null;
201 QueryParams queryParams = null;
202 SearchableEntity sourceEntity = null;
207 * Here is where we need to make a dip to elastic-search for the self-link by entity-id (link
210 dataCollectionResult = esAdapter.retrieveEntityById(endpointEConfig.getEsIpAddress(),
211 endpointEConfig.getEsServerPort(),schemaEConfig.getIndexName(),
212 schemaEConfig.getIndexDocType(), queryRequest.getHashId());
213 sourceEntity = extractSearchableEntityFromElasticEntity(dataCollectionResult);
215 if (sourceEntity != null) {
216 sourceEntity.generateId();
219 queryParams = new QueryParams();
220 queryParams.setSearchTargetNodeId(queryRequest.getHashId());
222 } catch (Exception e1) {
223 LOG.error(AaiUiMsgs.FAILED_TO_GET_NODES_QUERY_RESULT, e1.getLocalizedMessage());
224 dataCollectionResult = new OperationResult(500, "Failed to get nodes-query result from AAI");
227 if (dataCollectionResult.getResultCode() == 200) {
229 String d3OutputJsonOutput = null;
233 d3OutputJsonOutput = getVisualizationOutputBasedonGenericQuery( sourceEntity, queryParams, queryRequest);
235 if (LOG.isDebugEnabled()) {
236 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
237 "Generated D3" + " output as json = " + d3OutputJsonOutput);
240 if (d3OutputJsonOutput != null) {
241 returnValue.setResultCode(200);
242 returnValue.setResult(d3OutputJsonOutput);
244 returnValue.setResult(500, "Failed to generate D3 graph visualization");
247 } catch (Exception exc) {
248 returnValue.setResult(500,
249 "Failed to generate D3 graph visualization, due to a servlet exception.");
250 LOG.error(AaiUiMsgs.ERROR_D3_GRAPH_VISUALIZATION, exc.getLocalizedMessage());
253 returnValue.setResult(dataCollectionResult.getResultCode(), dataCollectionResult.getResult());
262 * Gets the visualization output basedon generic query.
264 * @param searchtargetEntity entity that will be used to start visualization flow
265 * @param queryParams the query params
266 * @return the visualization output basedon generic query
267 * @throws ServletException the servlet exception
270 private String getVisualizationOutputBasedonGenericQuery(SearchableEntity searchtargetEntity,
271 QueryParams queryParams, QueryRequest request) throws ServletException {
273 long opStartTimeInMs = System.currentTimeMillis();
275 VisualizationTransformer transformer = null;
277 transformer = new VisualizationTransformer(visualizationConfigs, subConfig);
278 } catch (Exception exc) {
279 throw new ServletException(
280 "Failed to create VisualizationTransformer instance because of execption", exc);
283 VisualizationContext visContext = null;
284 long contextId = secureRandom.nextLong();
286 if ( visualizationConfigs.isGizmoEnabled()) {
287 visContext = new BaseGizmoVisualizationContext(contextId, this.gizmoAdapter, aaiExecutorService,
288 this.visualizationConfigs, oxmEntityLookup);
290 visContext = new BaseVisualizationContext(contextId, this.aaiAdapter, aaiExecutorService,
291 this.visualizationConfigs, oxmEntityLookup);
294 contextMap.putIfAbsent(contextId, visContext);
295 } catch (Exception e1) {
296 LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT,
297 "While building Visualization Context, " + e1.getLocalizedMessage());
298 throw new ServletException(e1);
301 String jsonResponse = null;
303 long startTimeInMs = System.currentTimeMillis();
305 visContext.processSelfLinks(searchtargetEntity, queryParams);
306 contextMap.remove(contextId);
308 logOptime("collectSelfLinkNodes()", startTimeInMs);
311 * Flatten the graphs into a set of Graph and Link nodes. In this method I want the node graph
312 * resulting from the edge-tag-query to be represented first, and then we'll layer in
315 long overlayDataStartTimeInMs = System.currentTimeMillis();
317 Map<String, ActiveInventoryNode> cachedNodeMap = visContext.getNodeCache();
319 if (LOG.isDebugEnabled()) {
321 StringBuilder sb = new StringBuilder(128);
323 sb.append("\nCached Node Map:\n");
324 for (String k : cachedNodeMap.keySet()) {
326 sb.append("\n").append(cachedNodeMap.get(k).dumpNodeTree(true));
329 LOG.debug(AaiUiMsgs.DEBUG_GENERIC, sb.toString());
332 transformer.buildFlatNodeArrayFromGraphCollection(cachedNodeMap);
333 transformer.buildLinksFromGraphCollection(cachedNodeMap);
336 * - Apply configuration-driven styling
337 * - Build the final transformation response object
338 * - Use information we have to populate the GraphMeta object
341 transformer.addSearchTargetAttributesToRootNode();
343 GraphMeta graphMeta = new GraphMeta();
345 D3VisualizationOutput output = null;
348 .generateVisualizationOutput((System.currentTimeMillis() - opStartTimeInMs), graphMeta);
349 } catch (JsonProcessingException exc) {
350 throw new ServletException("Caught an exception while generation visualization output", exc);
351 } catch (IOException exc) {
352 LOG.error(AaiUiMsgs.FAILURE_TO_PROCESS_REQUEST, exc.getLocalizedMessage());
355 output.setInlineMessage(visContext.getInlineMessage());
356 output.getGraphMeta().setNumLinkResolveFailed(visContext.getNumFailedLinkResolve());
357 output.getGraphMeta().setNumLinksResolvedSuccessfullyFromCache(
358 visContext.getNumSuccessfulLinkResolveFromCache());
359 output.getGraphMeta().setNumLinksResolvedSuccessfullyFromServer(
360 visContext.getNumSuccessfulLinkResolveFromFromServer());
363 jsonResponse = transformer.convertVisualizationOutputToJson(output);
364 } catch (JsonProcessingException jpe) {
365 throw new ServletException(
366 "Caught an exception while converting visualization output to json", jpe);
369 logOptime("[build flat node array, add relationship data, search target,"
370 + " color scheme, and generate visualization output]", overlayDataStartTimeInMs);
372 logOptime("doFilter()", opStartTimeInMs);
378 public void shutdown() {
379 aaiExecutorService.shutdown();