diff options
Diffstat (limited to 'sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java')
-rw-r--r-- | sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java new file mode 100644 index 0000000..4c393e1 --- /dev/null +++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java @@ -0,0 +1,407 @@ +/** + * ============LICENSE_START=================================================== + * SPARKY (AAI UI service) + * ============================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ============================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================================== + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.aai.sparky.search; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.component.restlet.RestletConstants; +import org.json.JSONArray; +import org.json.JSONObject; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.sparky.dal.ElasticSearchAdapter; +import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder; +import org.onap.aai.sparky.logging.AaiUiMsgs; +import org.onap.aai.sparky.util.NodeUtils; +import org.onap.aai.sparky.util.RestletUtils; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.ClientInfo; +import org.restlet.data.MediaType; +import org.restlet.data.Status; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +/** + * Receives and processes Entity Count History requests + */ +public class EntityCountHistoryProcessor implements Processor { + + private static final Logger LOG = + LoggerFactory.getInstance().getLogger(EntityCountHistoryProcessor.class); + + private static final long serialVersionUID = 1L; + + private ElasticSearchAdapter elasticSearchAdapter = null; + private ObjectMapper mapper; + + private static final String SEARCH_PRETTY_STRING = "_search?pretty"; + private static final String TYPE = "type"; + private static final String TABLE = "table"; + private static final String GRAPH = "graph"; + + private List<String> entityTypesToSummarize; + private List<String> vnfEntityTypes; + + private String entityCountHistoryIndexName; + + private boolean summarizeVnfs = false; + + private RestletUtils restletUtils = new RestletUtils(); + + /** + * Instantiates a new Entity Count History + */ + + public EntityCountHistoryProcessor(ElasticSearchAdapter elasticSearchAdapter, + String entityTypesToSummarizeDelimitedList, String vnfEntityTypesDelimitedList, String entityCountHistoryIndexName) { + + this.elasticSearchAdapter = elasticSearchAdapter; + this.entityCountHistoryIndexName = entityCountHistoryIndexName; + + entityTypesToSummarize = + Arrays.asList(entityTypesToSummarizeDelimitedList.toLowerCase().split("[\\s,]+")); + + vnfEntityTypes = + Arrays.asList(vnfEntityTypesDelimitedList.toLowerCase().split("[\\s,]+")); + + summarizeVnfs = vnfEntityTypesDelimitedList.toLowerCase().contains("vnf"); + + this.mapper = new ObjectMapper(); + this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + } + + /** + * Processes a entity count history search request + * + * @param exchange The Exchange object generated by Apache Camel for the incoming request + */ + + @Override + public void process(Exchange exchange) throws Exception { + + Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class); + Response restletResponse = + exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class); + + Object xTransactionId = exchange.getIn().getHeader("X-TransactionId"); + if (xTransactionId == null) { + xTransactionId = NodeUtils.getRandomTxnId(); + } + + Object partnerName = exchange.getIn().getHeader("X-FromAppId"); + if (partnerName == null) { + partnerName = "Browser"; + } + + /* + * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log + * entry which includes client (e.g. browser) information + */ + request.setLoggable(false); + + ClientInfo clientInfo = request.getClientInfo(); + MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName, + clientInfo.getAddress() + ":" + clientInfo.getPort()); + + String typeParameter = getTypeParameter(exchange); + + if (null != typeParameter && !typeParameter.isEmpty()) { + OperationResult operationResult = null; + + try { + operationResult = getResults(restletResponse, typeParameter); + restletResponse.setEntity(operationResult.getResult(), MediaType.APPLICATION_JSON); + } catch (Exception exc) { + LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage()); + } + } else { + LOG.error(AaiUiMsgs.RESOURCE_NOT_FOUND, request.getOriginalRef().toString()); + String errorMessage = + restletUtils.generateJsonErrorResponse("Unsupported request. Resource not found."); + restletResponse.setEntity(errorMessage, MediaType.APPLICATION_JSON); + restletResponse.setStatus(Status.CLIENT_ERROR_NOT_FOUND); + } + + exchange.getOut().setBody(restletResponse); + } + + + /** + * Format line graph output + * + * @param results The results + * @return The JSON object + * @throws JsonProcessingException The JSON processing exception + */ + public JSONObject formatLineGraphOutput(String results) throws JsonProcessingException { + Map<Long, Long> countByDateMap = new HashMap<Long, Long>(); + + JsonNode resultNode = null; + + JSONObject finalResult = new JSONObject(); + JSONArray finalResultArr = new JSONArray(); + + try { + resultNode = mapper.readTree(results); + + final JsonNode bucketsNode = getBucketsNode(resultNode); + + if (bucketsNode.isArray()) { + + for (final JsonNode entityNode : bucketsNode) { + final JsonNode dateBucketNode = entityNode.get("group_by_date").get("buckets"); + if (dateBucketNode.isArray()) { + for (final JsonNode dateBucket : dateBucketNode) { + Long date = dateBucket.get("key").asLong(); + final JsonNode countBucketNode = + dateBucket.get("sort_by_date").get("hits").get("hits"); + + if (countBucketNode.isArray()) { + final JsonNode latestEntityNode = countBucketNode.get(0); + + long currentCount = latestEntityNode.get("_source").get("count").asLong(); + if (countByDateMap.containsKey(date)) { + // add to the value if map already contains this date + currentCount += countByDateMap.get(date); + } + + countByDateMap.put(date, currentCount); + } + } + + } + } + } + + /* + * Sort the map by epoch timestamp + */ + Map<Long, Long> sortedMap = new TreeMap<Long, Long>(countByDateMap); + for (Entry<Long, Long> entry : sortedMap.entrySet()) { + JSONObject dateEntry = new JSONObject(); + dateEntry.put("date", entry.getKey()); + dateEntry.put("count", entry.getValue()); + finalResultArr.put(dateEntry); + } + + } catch (Exception exc) { + LOG.warn(AaiUiMsgs.ERROR_BUILDING_SEARCH_RESPONSE, exc.getLocalizedMessage()); + } + + return finalResult.put("result", finalResultArr); + } + + /** + * Format table output + * + * @param results The results + * @return The JSON object + * @throws JsonProcessingException The JSON processing exception + */ + public JSONObject formatTableOutput(String results) throws JsonProcessingException { + JsonNode resultNode = null; + + JSONObject finalResult = new JSONObject(); + JSONArray entitiesArr = new JSONArray(); + + Map<String, Long> entityCountInTable = initializeEntityMap(); + + long vnfCount = 0; + + try { + resultNode = mapper.readTree(results); + + final JsonNode bucketsNode = getBucketsNode(resultNode); + if (bucketsNode.isArray()) { + + for (final JsonNode entityNode : bucketsNode) { + String entityType = entityNode.get("key").asText(); + boolean isAVnf = vnfEntityTypes.contains(entityType); + long countValue = 0; + + if (isAVnf || entityCountInTable.get(entityType) != null) { + final JsonNode hitsBucketNode = entityNode.get("sort_by_date").get("hits").get("hits"); + if (hitsBucketNode.isArray()) { + // the first bucket will be the latest + final JsonNode hitNode = hitsBucketNode.get(0); + + countValue = hitNode.get("_source").get("count").asLong(); + + /* + * Special case: Add all the VNF types together to get aggregate count + */ + if (summarizeVnfs && isAVnf) { + vnfCount += countValue; + countValue = vnfCount; + entityType = "vnf"; + } + + entityCountInTable.replace(entityType, countValue); + } + } + + } + } + for (Entry<String, Long> entry : entityCountInTable.entrySet()) { + JSONObject entityType = new JSONObject(); + entityType.put("key", entry.getKey()); + entityType.put("doc_count", entry.getValue()); + entitiesArr.put(entityType); + } + + finalResult.put("result", entitiesArr); + + } catch (Exception exc) { + LOG.warn(AaiUiMsgs.ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY, exc.getLocalizedMessage()); + } + + return finalResult; + } + + /** + * Gets the results + * + * @param response The response + * @param type The type + * @return The results + */ + public OperationResult getResults(Response response, String type) { + OperationResult operationResult = new OperationResult(); + + String reqPayload = EntityHistoryQueryBuilder.getQuery(type).toString(); + + try { + final String fullUrlStr = elasticSearchAdapter + .buildElasticSearchUrlForApi(entityCountHistoryIndexName, SEARCH_PRETTY_STRING); + + OperationResult opResult = elasticSearchAdapter.doPost(fullUrlStr, reqPayload, + javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE); + + JSONObject finalOutput = null; + if (type.equalsIgnoreCase(TABLE)) { + finalOutput = formatTableOutput(opResult.getResult()); + } else if (type.equalsIgnoreCase(GRAPH)) { + finalOutput = formatLineGraphOutput(opResult.getResult()); + } + + if (finalOutput != null) { + response.setEntity(finalOutput.toString(), MediaType.APPLICATION_JSON); + operationResult.setResult(finalOutput.toString()); + } + } catch (JsonProcessingException exc) { + restletUtils.handleRestletErrors(LOG, "Unable to map JSONpayload", exc, response); + } + + return operationResult; + } + + /** + * Gets the buckets node + * + * @param node The node + * @return The buckets node + * @throws Exception The exception + */ + public JsonNode getBucketsNode(JsonNode node) throws Exception { + if (node.get("aggregations").get("group_by_entityType").get("buckets") != null) { + return node.get("aggregations").get("group_by_entityType").get("buckets"); + } else { + throw new Exception("Failed to map JSON response"); + } + } + + /** + * Initialize entity map + * + * @return the map + */ + private Map<String, Long> initializeEntityMap() { + Map<String, Long> entityMap = new HashMap<String, Long>(); + for (String entity : entityTypesToSummarize) { + entityMap.put(entity, (long) 0); + } + + return entityMap; + } + + /** + * Extracts the "type" query parameter from the request URI + * + * @param exchange + * @return String containing the value of the "type" query parameter of the request. Returns null + * if no "type" parameter found + */ + public String getTypeParameter(Exchange exchange) { + String typeParameter = null; + + String requestUriParameterString = exchange.getIn().getHeader("CamelHttpQuery", String.class); + + if (null != requestUriParameterString) { + String[] requestParameterParts = requestUriParameterString.split("&"); + + String[] parameter = requestParameterParts[0].split("="); + String currentParameterKey = parameter[0]; + + if (null != currentParameterKey && !currentParameterKey.isEmpty()) { + // Check if we're looking at the "type" parameter key + if (currentParameterKey.equals(TYPE)) { + boolean uriIncludesTypeParameterValue = + (parameter.length >= 2) && !parameter[1].isEmpty(); + + if (uriIncludesTypeParameterValue) { + String typeParameterValue = parameter[1]; + + // Is the parameter value one that we return data for? + if (typeParameterValue.equalsIgnoreCase(TABLE) + || typeParameterValue.equalsIgnoreCase(GRAPH)) { + typeParameter = typeParameterValue; + } + } + } + } + } + + return typeParameter; + } + + + public void setRestletUtils(RestletUtils restletUtils) { + this.restletUtils = restletUtils; + } + +} |