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.search;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
31 import java.util.Map.Entry;
32 import java.util.TreeMap;
34 import org.apache.camel.Exchange;
35 import org.apache.camel.Processor;
36 import org.apache.camel.component.restlet.RestletConstants;
37 import org.json.JSONArray;
38 import org.json.JSONObject;
39 import org.onap.aai.cl.api.Logger;
40 import org.onap.aai.cl.eelf.LoggerFactory;
41 import org.onap.aai.cl.mdc.MdcContext;
42 import org.onap.aai.restclient.client.OperationResult;
43 import org.onap.aai.sparky.dal.ElasticSearchAdapter;
44 import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder;
45 import org.onap.aai.sparky.logging.AaiUiMsgs;
46 import org.onap.aai.sparky.util.NodeUtils;
47 import org.onap.aai.sparky.util.RestletUtils;
48 import org.restlet.Request;
49 import org.restlet.Response;
50 import org.restlet.data.ClientInfo;
51 import org.restlet.data.MediaType;
52 import org.restlet.data.Status;
54 import com.fasterxml.jackson.core.JsonProcessingException;
55 import com.fasterxml.jackson.databind.JsonNode;
56 import com.fasterxml.jackson.databind.ObjectMapper;
57 import com.fasterxml.jackson.databind.SerializationFeature;
60 * Receives and processes Entity Count History requests
62 public class EntityCountHistoryProcessor implements Processor {
64 private static final Logger LOG =
65 LoggerFactory.getInstance().getLogger(EntityCountHistoryProcessor.class);
67 private static final long serialVersionUID = 1L;
69 private ElasticSearchAdapter elasticSearchAdapter = null;
70 private ObjectMapper mapper;
72 private static final String SEARCH_PRETTY_STRING = "_search?pretty";
73 private static final String TYPE = "type";
74 private static final String TABLE = "table";
75 private static final String GRAPH = "graph";
77 private List<String> entityTypesToSummarize;
78 private List<String> vnfEntityTypes;
80 private String entityCountHistoryIndexName;
82 private boolean summarizeVnfs = false;
84 private RestletUtils restletUtils = new RestletUtils();
87 * Instantiates a new Entity Count History
90 public EntityCountHistoryProcessor(ElasticSearchAdapter elasticSearchAdapter,
91 String entityTypesToSummarizeDelimitedList, String vnfEntityTypesDelimitedList, String entityCountHistoryIndexName) {
93 this.elasticSearchAdapter = elasticSearchAdapter;
94 this.entityCountHistoryIndexName = entityCountHistoryIndexName;
96 entityTypesToSummarize =
97 Arrays.asList(entityTypesToSummarizeDelimitedList.toLowerCase().split("[\\s,]+"));
100 Arrays.asList(vnfEntityTypesDelimitedList.toLowerCase().split("[\\s,]+"));
102 summarizeVnfs = vnfEntityTypesDelimitedList.toLowerCase().contains("vnf");
104 this.mapper = new ObjectMapper();
105 this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
109 * Processes a entity count history search request
111 * @param exchange The Exchange object generated by Apache Camel for the incoming request
115 public void process(Exchange exchange) throws Exception {
117 Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
118 Response restletResponse =
119 exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class);
121 Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
122 if (xTransactionId == null) {
123 xTransactionId = NodeUtils.getRandomTxnId();
126 Object partnerName = exchange.getIn().getHeader("X-FromAppId");
127 if (partnerName == null) {
128 partnerName = "Browser";
132 * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log
133 * entry which includes client (e.g. browser) information
135 request.setLoggable(false);
137 ClientInfo clientInfo = request.getClientInfo();
138 MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName,
139 clientInfo.getAddress() + ":" + clientInfo.getPort());
141 String typeParameter = getTypeParameter(exchange);
143 if (null != typeParameter && !typeParameter.isEmpty()) {
144 OperationResult operationResult = null;
147 operationResult = getResults(restletResponse, typeParameter);
148 restletResponse.setEntity(operationResult.getResult(), MediaType.APPLICATION_JSON);
149 } catch (Exception exc) {
150 LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage());
153 LOG.error(AaiUiMsgs.RESOURCE_NOT_FOUND, request.getOriginalRef().toString());
154 String errorMessage =
155 restletUtils.generateJsonErrorResponse("Unsupported request. Resource not found.");
156 restletResponse.setEntity(errorMessage, MediaType.APPLICATION_JSON);
157 restletResponse.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
160 exchange.getOut().setBody(restletResponse);
165 * Format line graph output
167 * @param results The results
168 * @return The JSON object
169 * @throws JsonProcessingException The JSON processing exception
171 public JSONObject formatLineGraphOutput(String results) throws JsonProcessingException {
172 Map<Long, Long> countByDateMap = new HashMap<Long, Long>();
174 JsonNode resultNode = null;
176 JSONObject finalResult = new JSONObject();
177 JSONArray finalResultArr = new JSONArray();
180 resultNode = mapper.readTree(results);
182 final JsonNode bucketsNode = getBucketsNode(resultNode);
184 if (bucketsNode.isArray()) {
186 for (final JsonNode entityNode : bucketsNode) {
187 final JsonNode dateBucketNode = entityNode.get("group_by_date").get("buckets");
188 if (dateBucketNode.isArray()) {
189 for (final JsonNode dateBucket : dateBucketNode) {
190 Long date = dateBucket.get("key").asLong();
191 final JsonNode countBucketNode =
192 dateBucket.get("sort_by_date").get("hits").get("hits");
194 if (countBucketNode.isArray()) {
195 final JsonNode latestEntityNode = countBucketNode.get(0);
197 long currentCount = latestEntityNode.get("_source").get("count").asLong();
198 if (countByDateMap.containsKey(date)) {
199 // add to the value if map already contains this date
200 currentCount += countByDateMap.get(date);
203 countByDateMap.put(date, currentCount);
212 * Sort the map by epoch timestamp
214 Map<Long, Long> sortedMap = new TreeMap<Long, Long>(countByDateMap);
215 for (Entry<Long, Long> entry : sortedMap.entrySet()) {
216 JSONObject dateEntry = new JSONObject();
217 dateEntry.put("date", entry.getKey());
218 dateEntry.put("count", entry.getValue());
219 finalResultArr.put(dateEntry);
222 } catch (Exception exc) {
223 LOG.warn(AaiUiMsgs.ERROR_BUILDING_SEARCH_RESPONSE, exc.getLocalizedMessage());
226 return finalResult.put("result", finalResultArr);
230 * Format table output
232 * @param results The results
233 * @return The JSON object
234 * @throws JsonProcessingException The JSON processing exception
236 public JSONObject formatTableOutput(String results) throws JsonProcessingException {
237 JsonNode resultNode = null;
239 JSONObject finalResult = new JSONObject();
240 JSONArray entitiesArr = new JSONArray();
242 Map<String, Long> entityCountInTable = initializeEntityMap();
247 resultNode = mapper.readTree(results);
249 final JsonNode bucketsNode = getBucketsNode(resultNode);
250 if (bucketsNode.isArray()) {
252 for (final JsonNode entityNode : bucketsNode) {
253 String entityType = entityNode.get("key").asText();
254 boolean isAVnf = vnfEntityTypes.contains(entityType);
257 if (isAVnf || entityCountInTable.get(entityType) != null) {
258 final JsonNode hitsBucketNode = entityNode.get("sort_by_date").get("hits").get("hits");
259 if (hitsBucketNode.isArray()) {
260 // the first bucket will be the latest
261 final JsonNode hitNode = hitsBucketNode.get(0);
263 countValue = hitNode.get("_source").get("count").asLong();
266 * Special case: Add all the VNF types together to get aggregate count
268 if (summarizeVnfs && isAVnf) {
269 vnfCount += countValue;
270 countValue = vnfCount;
274 entityCountInTable.replace(entityType, countValue);
280 for (Entry<String, Long> entry : entityCountInTable.entrySet()) {
281 JSONObject entityType = new JSONObject();
282 entityType.put("key", entry.getKey());
283 entityType.put("doc_count", entry.getValue());
284 entitiesArr.put(entityType);
287 finalResult.put("result", entitiesArr);
289 } catch (Exception exc) {
290 LOG.warn(AaiUiMsgs.ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY, exc.getLocalizedMessage());
299 * @param response The response
300 * @param type The type
301 * @return The results
303 public OperationResult getResults(Response response, String type) {
304 OperationResult operationResult = new OperationResult();
306 String reqPayload = EntityHistoryQueryBuilder.getQuery(type).toString();
309 final String fullUrlStr = elasticSearchAdapter
310 .buildElasticSearchUrlForApi(entityCountHistoryIndexName, SEARCH_PRETTY_STRING);
312 OperationResult opResult = elasticSearchAdapter.doPost(fullUrlStr, reqPayload,
313 javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
315 JSONObject finalOutput = null;
316 if (type.equalsIgnoreCase(TABLE)) {
317 finalOutput = formatTableOutput(opResult.getResult());
318 } else if (type.equalsIgnoreCase(GRAPH)) {
319 finalOutput = formatLineGraphOutput(opResult.getResult());
322 if (finalOutput != null) {
323 response.setEntity(finalOutput.toString(), MediaType.APPLICATION_JSON);
324 operationResult.setResult(finalOutput.toString());
326 } catch (JsonProcessingException exc) {
327 restletUtils.handleRestletErrors(LOG, "Unable to map JSONpayload", exc, response);
330 return operationResult;
334 * Gets the buckets node
336 * @param node The node
337 * @return The buckets node
338 * @throws Exception The exception
340 public JsonNode getBucketsNode(JsonNode node) throws Exception {
341 if (node.get("aggregations").get("group_by_entityType").get("buckets") != null) {
342 return node.get("aggregations").get("group_by_entityType").get("buckets");
344 throw new Exception("Failed to map JSON response");
349 * Initialize entity map
353 private Map<String, Long> initializeEntityMap() {
354 Map<String, Long> entityMap = new HashMap<String, Long>();
355 for (String entity : entityTypesToSummarize) {
356 entityMap.put(entity, (long) 0);
363 * Extracts the "type" query parameter from the request URI
366 * @return String containing the value of the "type" query parameter of the request. Returns null
367 * if no "type" parameter found
369 public String getTypeParameter(Exchange exchange) {
370 String typeParameter = null;
372 String requestUriParameterString = exchange.getIn().getHeader("CamelHttpQuery", String.class);
374 if (null != requestUriParameterString) {
375 String[] requestParameterParts = requestUriParameterString.split("&");
377 String[] parameter = requestParameterParts[0].split("=");
378 String currentParameterKey = parameter[0];
380 if (null != currentParameterKey && !currentParameterKey.isEmpty()) {
381 // Check if we're looking at the "type" parameter key
382 if (currentParameterKey.equals(TYPE)) {
383 boolean uriIncludesTypeParameterValue =
384 (parameter.length >= 2) && !parameter[1].isEmpty();
386 if (uriIncludesTypeParameterValue) {
387 String typeParameterValue = parameter[1];
389 // Is the parameter value one that we return data for?
390 if (typeParameterValue.equalsIgnoreCase(TABLE)
391 || typeParameterValue.equalsIgnoreCase(GRAPH)) {
392 typeParameter = typeParameterValue;
399 return typeParameter;
403 public void setRestletUtils(RestletUtils restletUtils) {
404 this.restletUtils = restletUtils;