summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java')
-rw-r--r--src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java417
1 files changed, 417 insertions, 0 deletions
diff --git a/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java b/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
new file mode 100644
index 0000000..e2eef7a
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
@@ -0,0 +1,417 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ================================================================================
+ * 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 is a trademark and service mark 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.elasticsearch.SearchAdapter;
+import org.onap.aai.sparky.dal.elasticsearch.config.ElasticSearchConfig;
+import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.RestletUtils;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+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 SearchAdapter search = null;
+ private ElasticSearchConfig elasticConfig = null;
+ private VisualizationConfigs visualConfigs = null;
+ private ObjectMapper mapper;
+
+ private static final String SEARCH_STRING = "_search";
+ private static final String TYPE = "type";
+ private static final String TABLE = "table";
+ private static final String GRAPH = "graph";
+
+ private List<String> vnfEntityTypesToSummarize;
+ private boolean summarizevnf = false;
+
+ private RestletUtils restletUtils = new RestletUtils();
+
+ /**
+ * Instantiates a new Entity Count History
+ */
+
+ public EntityCountHistoryProcessor(VisualizationConfigs visualizationConfigs) {
+
+ this.visualConfigs = visualizationConfigs;
+ vnfEntityTypesToSummarize =
+ Arrays.asList(visualConfigs.getVnfEntityTypes().toLowerCase().split("[\\s,]+"));
+ summarizevnf = visualConfigs.getEntityTypesToSummarize().toLowerCase().contains("vnf");
+ try {
+ if (elasticConfig == null) {
+ elasticConfig = ElasticSearchConfig.getConfig();
+ }
+
+ if (search == null) {
+ search = new SearchAdapter();
+ }
+ this.mapper = new ObjectMapper();
+ this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage());
+ }
+ }
+
+ /**
+ * 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 = vnfEntityTypesToSummarize.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 (summarizevnf && 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 requestString =
+ String.format("/%s/%s?pretty", elasticConfig.getEntityCountHistoryIndex(), SEARCH_STRING);
+
+ String reqPayload = EntityHistoryQueryBuilder.getQuery(type).toString();
+
+ try {
+ final String fullUrlStr = ServletUtils.getFullUrl(elasticConfig, requestString);
+ OperationResult opResult =
+ restletUtils.executePostQuery(LOG, search, response, fullUrlStr, reqPayload);
+
+ 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>();
+ String[] entityTypes = visualConfigs.getEntityTypesToSummarize().split(",");
+ for (String entity : entityTypes) {
+ 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 setElasticConfig(ElasticSearchConfig elasticConfig) {
+ this.elasticConfig = elasticConfig;
+ }
+
+ public void setRestletUtils(RestletUtils restletUtils) {
+ this.restletUtils = restletUtils;
+ }
+
+ public void setSearch(SearchAdapter search) {
+ this.search = search;
+ }
+}