2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.onap.aai.sparky.search;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.Map.Entry;
30 import java.util.TreeMap;
32 import org.apache.camel.Exchange;
33 import org.apache.camel.Processor;
34 import org.apache.camel.component.restlet.RestletConstants;
35 import org.json.JSONArray;
36 import org.json.JSONObject;
37 import org.onap.aai.cl.api.Logger;
38 import org.onap.aai.cl.eelf.LoggerFactory;
39 import org.onap.aai.cl.mdc.MdcContext;
40 import org.onap.aai.restclient.client.OperationResult;
41 import org.onap.aai.sparky.dal.elasticsearch.SearchAdapter;
42 import org.onap.aai.sparky.dal.elasticsearch.config.ElasticSearchConfig;
43 import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder;
44 import org.onap.aai.sparky.logging.AaiUiMsgs;
45 import org.onap.aai.sparky.logging.util.ServletUtils;
46 import org.onap.aai.sparky.util.NodeUtils;
47 import org.onap.aai.sparky.util.RestletUtils;
48 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
49 import org.restlet.Request;
50 import org.restlet.Response;
51 import org.restlet.data.ClientInfo;
52 import org.restlet.data.MediaType;
53 import org.restlet.data.Status;
55 import com.fasterxml.jackson.core.JsonProcessingException;
56 import com.fasterxml.jackson.databind.JsonNode;
57 import com.fasterxml.jackson.databind.ObjectMapper;
58 import com.fasterxml.jackson.databind.SerializationFeature;
61 * Receives and processes Entity Count History requests
63 public class EntityCountHistoryProcessor implements Processor {
65 private static final Logger LOG =
66 LoggerFactory.getInstance().getLogger(EntityCountHistoryProcessor.class);
68 private static final long serialVersionUID = 1L;
70 private SearchAdapter search = null;
71 private ElasticSearchConfig elasticConfig = null;
72 private VisualizationConfigs visualConfigs = null;
73 private ObjectMapper mapper;
75 private static final String SEARCH_STRING = "_search";
76 private static final String TYPE = "type";
77 private static final String TABLE = "table";
78 private static final String GRAPH = "graph";
80 private List<String> vnfEntityTypesToSummarize;
81 private boolean summarizevnf = false;
83 private RestletUtils restletUtils = new RestletUtils();
86 * Instantiates a new Entity Count History
89 public EntityCountHistoryProcessor(VisualizationConfigs visualizationConfigs) {
91 this.visualConfigs = visualizationConfigs;
92 vnfEntityTypesToSummarize =
93 Arrays.asList(visualConfigs.getVnfEntityTypes().toLowerCase().split("[\\s,]+"));
94 summarizevnf = visualConfigs.getEntityTypesToSummarize().toLowerCase().contains("vnf");
96 if (elasticConfig == null) {
97 elasticConfig = ElasticSearchConfig.getConfig();
100 if (search == null) {
101 search = new SearchAdapter();
103 this.mapper = new ObjectMapper();
104 this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
105 } catch (Exception exc) {
106 LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage());
111 * Processes a entity count history search request
113 * @param exchange The Exchange object generated by Apache Camel for the incoming request
117 public void process(Exchange exchange) throws Exception {
119 Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
120 Response restletResponse =
121 exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class);
123 Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
124 if (xTransactionId == null) {
125 xTransactionId = NodeUtils.getRandomTxnId();
128 Object partnerName = exchange.getIn().getHeader("X-FromAppId");
129 if (partnerName == null) {
130 partnerName = "Browser";
134 * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log
135 * entry which includes client (e.g. browser) information
137 request.setLoggable(false);
139 ClientInfo clientInfo = request.getClientInfo();
140 MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName,
141 clientInfo.getAddress() + ":" + clientInfo.getPort());
143 String typeParameter = getTypeParameter(exchange);
145 if (null != typeParameter && !typeParameter.isEmpty()) {
146 OperationResult operationResult = null;
149 operationResult = getResults(restletResponse, typeParameter);
150 restletResponse.setEntity(operationResult.getResult(), MediaType.APPLICATION_JSON);
151 } catch (Exception exc) {
152 LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage());
155 LOG.error(AaiUiMsgs.RESOURCE_NOT_FOUND, request.getOriginalRef().toString());
156 String errorMessage =
157 restletUtils.generateJsonErrorResponse("Unsupported request. Resource not found.");
158 restletResponse.setEntity(errorMessage, MediaType.APPLICATION_JSON);
159 restletResponse.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
162 exchange.getOut().setBody(restletResponse);
167 * Format line graph output
169 * @param results The results
170 * @return The JSON object
171 * @throws JsonProcessingException The JSON processing exception
173 public JSONObject formatLineGraphOutput(String results) throws JsonProcessingException {
174 Map<Long, Long> countByDateMap = new HashMap<Long, Long>();
176 JsonNode resultNode = null;
178 JSONObject finalResult = new JSONObject();
179 JSONArray finalResultArr = new JSONArray();
182 resultNode = mapper.readTree(results);
184 final JsonNode bucketsNode = getBucketsNode(resultNode);
186 if (bucketsNode.isArray()) {
188 for (final JsonNode entityNode : bucketsNode) {
189 final JsonNode dateBucketNode = entityNode.get("group_by_date").get("buckets");
190 if (dateBucketNode.isArray()) {
191 for (final JsonNode dateBucket : dateBucketNode) {
192 Long date = dateBucket.get("key").asLong();
193 final JsonNode countBucketNode =
194 dateBucket.get("sort_by_date").get("hits").get("hits");
196 if (countBucketNode.isArray()) {
197 final JsonNode latestEntityNode = countBucketNode.get(0);
199 long currentCount = latestEntityNode.get("_source").get("count").asLong();
200 if (countByDateMap.containsKey(date)) {
201 // add to the value if map already contains this date
202 currentCount += countByDateMap.get(date);
205 countByDateMap.put(date, currentCount);
214 * Sort the map by epoch timestamp
216 Map<Long, Long> sortedMap = new TreeMap<Long, Long>(countByDateMap);
217 for (Entry<Long, Long> entry : sortedMap.entrySet()) {
218 JSONObject dateEntry = new JSONObject();
219 dateEntry.put("date", entry.getKey());
220 dateEntry.put("count", entry.getValue());
221 finalResultArr.put(dateEntry);
224 } catch (Exception exc) {
225 LOG.warn(AaiUiMsgs.ERROR_BUILDING_SEARCH_RESPONSE, exc.getLocalizedMessage());
228 return finalResult.put("result", finalResultArr);
232 * Format table output
234 * @param results The results
235 * @return The JSON object
236 * @throws JsonProcessingException The JSON processing exception
238 public JSONObject formatTableOutput(String results) throws JsonProcessingException {
239 JsonNode resultNode = null;
241 JSONObject finalResult = new JSONObject();
242 JSONArray entitiesArr = new JSONArray();
244 Map<String, Long> entityCountInTable = initializeEntityMap();
249 resultNode = mapper.readTree(results);
251 final JsonNode bucketsNode = getBucketsNode(resultNode);
252 if (bucketsNode.isArray()) {
254 for (final JsonNode entityNode : bucketsNode) {
255 String entityType = entityNode.get("key").asText();
256 boolean isAVnf = vnfEntityTypesToSummarize.contains(entityType);
259 if (isAVnf || entityCountInTable.get(entityType) != null) {
260 final JsonNode hitsBucketNode = entityNode.get("sort_by_date").get("hits").get("hits");
261 if (hitsBucketNode.isArray()) {
262 // the first bucket will be the latest
263 final JsonNode hitNode = hitsBucketNode.get(0);
265 countValue = hitNode.get("_source").get("count").asLong();
268 * Special case: Add all the VNF types together to get aggregate count
270 if (summarizevnf && isAVnf) {
271 vnfCount += countValue;
272 countValue = vnfCount;
276 entityCountInTable.replace(entityType, countValue);
282 for (Entry<String, Long> entry : entityCountInTable.entrySet()) {
283 JSONObject entityType = new JSONObject();
284 entityType.put("key", entry.getKey());
285 entityType.put("doc_count", entry.getValue());
286 entitiesArr.put(entityType);
289 finalResult.put("result", entitiesArr);
291 } catch (Exception exc) {
292 LOG.warn(AaiUiMsgs.ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY, exc.getLocalizedMessage());
301 * @param response The response
302 * @param type The type
303 * @return The results
305 public OperationResult getResults(Response response, String type) {
306 OperationResult operationResult = new OperationResult();
308 String requestString =
309 String.format("/%s/%s?pretty", elasticConfig.getEntityCountHistoryIndex(), SEARCH_STRING);
311 String reqPayload = EntityHistoryQueryBuilder.getQuery(type).toString();
314 final String fullUrlStr = ServletUtils.getFullUrl(elasticConfig, requestString);
315 OperationResult opResult =
316 restletUtils.executePostQuery(LOG, search, response, fullUrlStr, reqPayload);
318 JSONObject finalOutput = null;
319 if (type.equalsIgnoreCase(TABLE)) {
320 finalOutput = formatTableOutput(opResult.getResult());
321 } else if (type.equalsIgnoreCase(GRAPH)) {
322 finalOutput = formatLineGraphOutput(opResult.getResult());
325 if (finalOutput != null) {
326 response.setEntity(finalOutput.toString(), MediaType.APPLICATION_JSON);
327 operationResult.setResult(finalOutput.toString());
329 } catch (JsonProcessingException exc) {
330 restletUtils.handleRestletErrors(LOG, "Unable to map JSONpayload", exc, response);
333 return operationResult;
337 * Gets the buckets node
339 * @param node The node
340 * @return The buckets node
341 * @throws Exception The exception
343 public JsonNode getBucketsNode(JsonNode node) throws Exception {
344 if (node.get("aggregations").get("group_by_entityType").get("buckets") != null) {
345 return node.get("aggregations").get("group_by_entityType").get("buckets");
347 throw new Exception("Failed to map JSON response");
352 * Initialize entity map
356 private Map<String, Long> initializeEntityMap() {
357 Map<String, Long> entityMap = new HashMap<String, Long>();
358 String[] entityTypes = visualConfigs.getEntityTypesToSummarize().split(",");
359 for (String entity : entityTypes) {
360 entityMap.put(entity, (long) 0);
367 * Extracts the "type" query parameter from the request URI
370 * @return String containing the value of the "type" query parameter of the request. Returns null
371 * if no "type" parameter found
373 public String getTypeParameter(Exchange exchange) {
374 String typeParameter = null;
376 String requestUriParameterString = exchange.getIn().getHeader("CamelHttpQuery", String.class);
378 if (null != requestUriParameterString) {
379 String[] requestParameterParts = requestUriParameterString.split("&");
381 String[] parameter = requestParameterParts[0].split("=");
382 String currentParameterKey = parameter[0];
384 if (null != currentParameterKey && !currentParameterKey.isEmpty()) {
385 // Check if we're looking at the "type" parameter key
386 if (currentParameterKey.equals(TYPE)) {
387 boolean uriIncludesTypeParameterValue =
388 (parameter.length >= 2) && !parameter[1].isEmpty();
390 if (uriIncludesTypeParameterValue) {
391 String typeParameterValue = parameter[1];
393 // Is the parameter value one that we return data for?
394 if (typeParameterValue.equalsIgnoreCase(TABLE)
395 || typeParameterValue.equalsIgnoreCase(GRAPH)) {
396 typeParameter = typeParameterValue;
403 return typeParameter;
406 public void setElasticConfig(ElasticSearchConfig elasticConfig) {
407 this.elasticConfig = elasticConfig;
410 public void setRestletUtils(RestletUtils restletUtils) {
411 this.restletUtils = restletUtils;
414 public void setSearch(SearchAdapter search) {
415 this.search = search;