From bf99eb77b31a4cfbc590762cc6ba669820c21439 Mon Sep 17 00:00:00 2001 From: rv871f Date: Tue, 20 Mar 2018 10:21:42 -0400 Subject: [PATCH] Process VNF event from spike Issue-ID: AAI-899 Change-Id: I2d056734e6af0fe0b4efe92681971e2b74153a0e Signed-off-by: rv871f --- .../datarouter/entity/SpikeAggregationEntity.java | 113 ++++ .../policy/AbstractSpikeEntityEventProcessor.java | 685 +++++++++++++++++++++ .../aai/datarouter/policy/EntityEventPolicy.java | 2 +- .../policy/SpikeAggregateGenericVnfProcessor.java | 117 ++++ .../policy/SpikeAutosuggestIndexProcessor.java | 254 ++++++++ .../policy/SpikeEntitySearchProcessor.java | 160 +++++ .../datarouter/policy/SpikeEventPolicyConfig.java | 90 +++ .../aai/datarouter/util/SearchServiceAgent.java | 32 + src/main/resources/aggregatevnf_schema.json | 17 + src/main/resources/autosuggest_schema.json | 31 + .../SpikeAggregateGenericVnfProcessorStubbed.java | 34 + .../SpikeAggregateGenericVnfProcessorTest.java | 111 ++++ .../policy/SpikeAutosuggestProcessorStubbed.java | 34 + .../policy/SpikeAutosuggestProcessorTest.java | 89 +++ .../policy/SpikeEntitySearchProcessorStubbed.java | 54 ++ .../policy/SpikeEntitySearchProcessorTest.java | 117 ++++ .../policy/SpikeEventPolicyConfigTest.java | 59 ++ 17 files changed, 1998 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/onap/aai/datarouter/entity/SpikeAggregationEntity.java create mode 100644 src/main/java/org/onap/aai/datarouter/policy/AbstractSpikeEntityEventProcessor.java create mode 100644 src/main/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessor.java create mode 100644 src/main/java/org/onap/aai/datarouter/policy/SpikeAutosuggestIndexProcessor.java create mode 100644 src/main/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessor.java create mode 100644 src/main/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfig.java create mode 100644 src/main/resources/aggregatevnf_schema.json create mode 100644 src/main/resources/autosuggest_schema.json create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorStubbed.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorTest.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorStubbed.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorTest.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorStubbed.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorTest.java create mode 100644 src/test/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfigTest.java diff --git a/src/main/java/org/onap/aai/datarouter/entity/SpikeAggregationEntity.java b/src/main/java/org/onap/aai/datarouter/entity/SpikeAggregationEntity.java new file mode 100644 index 0000000..cb620d8 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/entity/SpikeAggregationEntity.java @@ -0,0 +1,113 @@ +/** + * ============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.datarouter.entity; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.aai.datarouter.util.NodeUtils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * The Class SpikeAggregationEntity. Mimics functionality of SPIKEUI's AggregationEntity + */ +public class SpikeAggregationEntity implements DocumentStoreDataEntity, Serializable { + private String id; + private String link; + private String lastmodTimestamp; + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + @Override + public String getId() { + // make sure that deliveFields() is called before getting the id + return id; + } + + public void setId(String id) { + this.id = id; + } + + + public String getLastmodTimestamp() { + return lastmodTimestamp; + } + + public void setLastmodTimestamp(String lastmodTimestamp) { + this.lastmodTimestamp = lastmodTimestamp; + } + + + Map attributes = new HashMap<>(); + ObjectMapper mapper = new ObjectMapper(); + + /** + * Instantiates a new aggregation entity. + */ + public SpikeAggregationEntity() {} + + public void deriveFields(JsonNode uebPayload) { + + this.setId(NodeUtils.generateUniqueShaDigest(link)); + this.setLastmodTimestamp(Long.toString(System.currentTimeMillis())); + JsonNode entityNode = uebPayload.get("vertex").get("properties"); + Iterator> nodes = entityNode.fields(); + while (nodes.hasNext()) { + Map.Entry entry = (Map.Entry) nodes.next(); + attributes.put(entry.getKey(), entry.getValue().asText()); + } + } + + + + @Override + public String getAsJson() { + ObjectNode rootNode = mapper.createObjectNode(); + rootNode.put("link", this.getLink()); + rootNode.put("lastmodTimestamp", lastmodTimestamp); + for (Map.Entry entry : this.attributes.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + rootNode.put(key, value); + } + return rootNode.toString(); + } + + @Override + public String toString() { + return "AggregationEntity [id=" + id + ", link=" + link + ", attributes=" + attributes + + ", mapper=" + mapper + "]"; + } +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/AbstractSpikeEntityEventProcessor.java b/src/main/java/org/onap/aai/datarouter/policy/AbstractSpikeEntityEventProcessor.java new file mode 100644 index 0000000..9627365 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/AbstractSpikeEntityEventProcessor.java @@ -0,0 +1,685 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.datarouter.policy; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.internal.helper.DatabaseField; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.json.JSONException; +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.datarouter.entity.DocumentStoreDataEntity; +import org.onap.aai.datarouter.entity.OxmEntityDescriptor; +import org.onap.aai.datarouter.entity.SpikeEventEntity; +import org.onap.aai.datarouter.entity.SpikeEventVertex; +import org.onap.aai.datarouter.logging.EntityEventPolicyMsgs; +import org.onap.aai.datarouter.util.EntityOxmReferenceHelper; +import org.onap.aai.datarouter.util.ExternalOxmModelProcessor; +import org.onap.aai.datarouter.util.OxmModelLoader; +import org.onap.aai.datarouter.util.RouterServiceUtil; +import org.onap.aai.datarouter.util.SearchServiceAgent; +import org.onap.aai.restclient.client.Headers; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.rest.HttpUtil; +import org.slf4j.MDC; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + +public abstract class AbstractSpikeEntityEventProcessor implements Processor { + + protected static final String additionalInfo = "Response of SpikeEntityEventPolicy"; + private Collection externalOxmModelProcessors; + + + protected final String ACTION_CREATE = "create"; + private final String EVENT_VERTEX = "vertex"; + public final static String ACTION_DELETE = "delete"; + protected final String ACTION_UPDATE = "update"; + protected final String PROCESS_SPIKE_EVENT = "Process Spike Event"; + private final String OPERATION_KEY = "operation"; + + protected enum ResponseType { + SUCCESS, PARTIAL_SUCCESS, FAILURE; + } + + private final List SUPPORTED_ACTIONS = + Arrays.asList(ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE); + + Map oxmVersionContextMap = new HashMap<>(); + private String oxmVersion = null; + + /** Agent for communicating with the Search Service. */ + protected SearchServiceAgent searchAgent = null; + protected String searchIndexName; + protected String searchIndexSchema; + protected String createIndexUrl; + + protected Logger logger; + protected Logger metricsLogger; + protected ObjectMapper mapper; + + + public AbstractSpikeEntityEventProcessor(SpikeEventPolicyConfig config) + throws FileNotFoundException { + mapper = new ObjectMapper(); + LoggerFactory loggerFactoryInstance = LoggerFactory.getInstance(); + logger = loggerFactoryInstance.getLogger(AbstractSpikeEntityEventProcessor.class.getName()); + metricsLogger = + loggerFactoryInstance.getMetricsLogger(AbstractSpikeEntityEventProcessor.class.getName()); + + // Instantiate the agent that we will use for interacting with the Search Service. + searchAgent = new SearchServiceAgent(config.getSearchCertName(), config.getSearchKeystore(), + config.getSearchKeystorePwd(), AbstractSpikeEntityEventProcessor + .concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint()), + config.getSearchEndpointDocuments(), logger); + + this.externalOxmModelProcessors = new ArrayList<>(); + this.externalOxmModelProcessors.add(EntityOxmReferenceHelper.getInstance()); + OxmModelLoader.registerExternalOxmModelProcessors(externalOxmModelProcessors); + OxmModelLoader.loadModels(); + oxmVersionContextMap = OxmModelLoader.getVersionContextMap(); + parseLatestOxmVersion(); + } + + public String getCreateIndexUrl() { + return createIndexUrl; + } + + + public void setCreateIndexUrl(String createIndexUrl) { + this.createIndexUrl = createIndexUrl; + } + + public String getSearchIndexName() { + return searchIndexName; + } + + + public void setSearchIndexName(String searchIndexName) { + this.searchIndexName = searchIndexName; + } + + public String getSearchIndexSchema() { + return searchIndexSchema; + } + + + public void setSearchIndexSchema(String searchIndexSchema) { + this.searchIndexSchema = searchIndexSchema; + } + + protected void startup() { + + } + + /* + * Load the UEB JSON payload, any errors would result to a failure case response. + */ + protected JSONObject getUebContentAsJson(String payload, String contentKey) { + + JSONObject uebJsonObj; + JSONObject uebObjContent; + + try { + uebJsonObj = new JSONObject(payload); + } catch (JSONException e) { + logger.debug(EntityEventPolicyMsgs.UEB_INVALID_PAYLOAD_JSON_FORMAT, payload); + logger.error(EntityEventPolicyMsgs.UEB_INVALID_PAYLOAD_JSON_FORMAT, payload); + return null; + } + + if (uebJsonObj.has(contentKey)) { + uebObjContent = uebJsonObj.getJSONObject(contentKey); + } else { + logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey); + logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey); + return null; + } + + return uebObjContent; + } + public abstract void process(Exchange exchange) throws Exception; + + + private void parseLatestOxmVersion() { + int latestVersion = -1; + if (oxmVersionContextMap != null) { + Iterator it = oxmVersionContextMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + + String version = pair.getKey().toString(); + int versionNum = Integer.parseInt(version.substring(1, version.length())); + + if (versionNum > latestVersion) { + latestVersion = versionNum; + oxmVersion = pair.getKey().toString(); + } + + logger.info(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_FOUND, pair.getKey().toString()); + } + } else { + logger.error(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_MISSING, ""); + } + } + + + + /** + * This will be used in: updateSearchEntityWithCrossEntityReference not this scope Convert object + * to json. + * + * @param object the object + * @param pretty the pretty + * @return the string + * @throws JsonProcessingException the json processing exception + * + * protected static String convertObjectToJson(Object object, boolean pretty) throws + * JsonProcessingException { ObjectWriter ow; + * + * if (pretty) { ow = new ObjectMapper().writer().withDefaultPrettyPrinter(); + * + * } else { ow = new ObjectMapper().writer(); } + * + * return ow.writeValueAsString(object); } + */ + + protected void returnWithError(Exchange exchange, String payload, String errorMsg) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, errorMsg); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, errorMsg, payload); + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + } + + private boolean isJSONValid(String test) { + try { + new JSONObject(test); + } catch (JSONException ex) { + return false; + } + return true; + } + + + + protected String getSpikeEventAction(Exchange exchange, String uebPayload) { + JSONObject mainJson = new JSONObject(uebPayload); + String action = mainJson.getString(OPERATION_KEY); + if (action == null || !SUPPORTED_ACTIONS.contains(action.toLowerCase())) { + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Unrecognized action '" + action + "'", uebPayload); + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Unrecognized action '" + action + "'"); + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + return action; + } + + protected String getExchangeBody(Exchange exchange) { + String uebPayload = exchange.getIn().getBody().toString(); + if (uebPayload == null || !isJSONValid(uebPayload)) { + uebPayload = exchange.getIn().getBody(String.class); + if (uebPayload == null || !isJSONValid(uebPayload)) { + returnWithError(exchange, uebPayload, "Invalid Payload"); + return null; + } + } + return uebPayload; + } + + protected SpikeEventVertex populateEventVertex(Exchange exchange, String uebPayload) + throws Exception { + + // Load the UEB payload data, any errors will result in a failure and discard + + JSONObject spikeObjVertex = getUebContentAsJson(uebPayload, EVENT_VERTEX); + if (spikeObjVertex == null) { + returnWithError(exchange, uebPayload, "Payload is missing " + EVENT_VERTEX); + return null; + } + + SpikeEventVertex eventVertex = initializeSpikeEventVertex(spikeObjVertex.toString()); + return eventVertex; + } + + protected DynamicJAXBContext readOxm(Exchange exchange, String uebPayload) { + DynamicJAXBContext oxmJaxbContext = loadOxmContext(oxmVersion.toLowerCase()); + if (oxmJaxbContext == null) { + logger.error(EntityEventPolicyMsgs.OXM_VERSION_NOT_SUPPORTED, oxmVersion); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "OXM version mismatch", uebPayload); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + return oxmJaxbContext; + } + + + protected String getEntityType(Exchange exchange, SpikeEventVertex eventVertex, + String uebPayload) { + + String entityType = eventVertex.getType(); + if (entityType == null || entityType.isEmpty()) { + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Payload header missing entity type", uebPayload); + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload header missing entity type"); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + return entityType; + } + + + + protected String getEntityLink(Exchange exchange, SpikeEventVertex eventVertex, + String uebPayload) { + String entityKey = eventVertex.getKey(); + if (entityKey == null || entityKey.isEmpty()) { + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload vertex missing entity key", + uebPayload); + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload vertex missing entity key"); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + //EntityLink never can be null if entityKey is not null. no need to check + return eventVertex.getEntityLink(); + + } + + + + /* + * Use the OXM Model to determine the primary key field name based on the entity-type + */ + protected SpikeEventEntity populateSpikeEventEntity(Exchange exchange, + SpikeEventEntity spikeEventEntity, DynamicJAXBContext oxmJaxbContext, String entityType, + String action, String uebPayload, String oxmEntityType, List searchableAttr) { + + String entityPrimaryKeyFieldName = + getEntityPrimaryKeyFieldName(oxmJaxbContext, uebPayload, oxmEntityType, entityType); + if (entityPrimaryKeyFieldName == null) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload missing primary key attribute"); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Payload missing primary key attribute", uebPayload); + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + String entityPrimaryKeyFieldValue = lookupValueUsingKey(uebPayload, entityPrimaryKeyFieldName); + if (entityPrimaryKeyFieldValue.isEmpty()) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload missing primary value attribute"); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Payload missing primary value attribute", uebPayload); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + + + if (!getSearchTags(spikeEventEntity, searchableAttr, uebPayload, action)) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload missing searchable attribute for entity type '" + entityType + "'"); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Payload missing searchable attribute for entity type '" + entityType + "'", uebPayload); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + spikeEventEntity.setEntityPrimaryKeyName(entityPrimaryKeyFieldName); + spikeEventEntity.setEntityPrimaryKeyValue(entityPrimaryKeyFieldName); + + try { + spikeEventEntity.deriveFields(); + + } catch (NoSuchAlgorithmException e) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest"); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest", + uebPayload); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + return spikeEventEntity; + } + + protected void setResponse(Exchange exchange, ResponseType responseType, String additionalInfo) { + + exchange.getOut().setHeader("ResponseType", responseType.toString()); + exchange.getOut().setBody(additionalInfo); + } + + + protected String getOxmEntityType(String entityType) { + + String[] entityTypeArr = entityType.split("-"); + String oxmEntityType = ""; + for (String entityWord : entityTypeArr) { + oxmEntityType += entityWord.substring(0, 1).toUpperCase() + entityWord.substring(1); + } + return oxmEntityType; + } + + protected List getSearchableAttibutes(DynamicJAXBContext oxmJaxbContext, String oxmEntityType, + String entityType, String uebPayload,Exchange exchange) { + List searchableAttr = + getOxmAttributes(oxmJaxbContext, oxmEntityType, entityType, "searchable"); + if (searchableAttr == null) { + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Searchable attribute not found for payload entity type '" + entityType + "'"); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Searchable attribute not found for payload entity type '" + entityType + "'", + uebPayload); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + return null; + } + return searchableAttr; + } + + + private SpikeEventVertex initializeSpikeEventVertex(String payload) { + + SpikeEventVertex eventVertex = null; + ObjectMapper mapper = new ObjectMapper(); + + // Make sure that were were actually passed in a valid string. + if (payload == null || payload.isEmpty()) { + logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_VERTEX); + logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_VERTEX); + + return eventVertex; + } + + // Marshal the supplied string into a UebEventHeader object. + try { + eventVertex = mapper.readValue(payload, SpikeEventVertex.class); + } catch (JsonProcessingException e) { + logger.error(EntityEventPolicyMsgs.UEB_FAILED_UEBEVENTHEADER_CONVERSION, e.toString()); + } catch (Exception e) { + logger.error(EntityEventPolicyMsgs.UEB_FAILED_UEBEVENTHEADER_CONVERSION, e.toString()); + } + + if (eventVertex != null) { + logger.debug(EntityEventPolicyMsgs.UEB_EVENT_HEADER_PARSED, eventVertex.toString()); + } + + return eventVertex; + } + + + private String getEntityPrimaryKeyFieldName(DynamicJAXBContext oxmJaxbContext, String payload, + String oxmEntityType, String entityType) { + + DynamicType entity = oxmJaxbContext.getDynamicType(oxmEntityType); + if (entity == null) { + return null; + } + + List list = entity.getDescriptor().getPrimaryKeyFields(); + if (list != null && !list.isEmpty()) { + String keyName = list.get(0).getName(); + return keyName.substring(0, keyName.indexOf('/')); + } + + return ""; + } + + private String lookupValueUsingKey(String payload, String key) throws JSONException { + JsonNode jsonNode = convertToJsonNode(payload); + return RouterServiceUtil.recursivelyLookupJsonPayload(jsonNode, key); + } + + + private JsonNode convertToJsonNode(String payload) { + + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = null; + try { + jsonNode = mapper.readTree(mapper.getJsonFactory().createJsonParser(payload)); + } catch (IOException e) { + logger.debug(EntityEventPolicyMsgs.FAILED_TO_PARSE_UEB_PAYLOAD, EVENT_VERTEX + " missing", + payload); + logger.error(EntityEventPolicyMsgs.FAILED_TO_PARSE_UEB_PAYLOAD, EVENT_VERTEX + " missing", + ""); + } + + return jsonNode; + } + + + private boolean getSearchTags(SpikeEventEntity spikeEventEntity, List searchableAttr, + String payload, String action) { + + boolean hasSearchableAttr = false; + for (String searchTagField : searchableAttr) { + String searchTagValue; + if (searchTagField.equalsIgnoreCase(spikeEventEntity.getEntityPrimaryKeyName())) { + searchTagValue = spikeEventEntity.getEntityPrimaryKeyValue(); + } else { + searchTagValue = this.lookupValueUsingKey(payload, searchTagField); + } + + if (searchTagValue != null && !searchTagValue.isEmpty()) { + hasSearchableAttr = true; + spikeEventEntity.addSearchTagWithKey(searchTagValue, searchTagField); + } + } + return hasSearchableAttr; + } + + /* + * Check if OXM version is available. If available, load it. + */ + private DynamicJAXBContext loadOxmContext(String version) { + if (version == null) { + logger.error(EntityEventPolicyMsgs.FAILED_TO_FIND_OXM_VERSION, version); + return null; + } + + return oxmVersionContextMap.get(version); + } + + private List getOxmAttributes(DynamicJAXBContext oxmJaxbContext, String oxmEntityType, + String entityType, String fieldName) { + + DynamicType entity = (DynamicType) oxmJaxbContext.getDynamicType(oxmEntityType); + if (entity == null) { + return null; + } + + /* + * Check for searchable XML tag + */ + List fieldValues = null; + Map properties = entity.getDescriptor().getProperties(); + for (Map.Entry entry : properties.entrySet()) { + if (entry.getKey().equalsIgnoreCase(fieldName)) { + fieldValues = Arrays.asList(entry.getValue().split(",")); + break; + } + } + + return fieldValues; + } + + protected SpikeEventEntity getPopulatedEntity(JsonNode entityNode, + OxmEntityDescriptor resultDescriptor) { + SpikeEventEntity d = new SpikeEventEntity(); + + d.setEntityType(resultDescriptor.getEntityName()); + + List primaryKeyValues = new ArrayList<>(); + List primaryKeyNames = new ArrayList<>(); + String pkeyValue; + + for (String keyName : resultDescriptor.getPrimaryKeyAttributeName()) { + pkeyValue = RouterServiceUtil.getNodeFieldAsText(entityNode, keyName); + if (pkeyValue != null) { + primaryKeyValues.add(pkeyValue); + primaryKeyNames.add(keyName); + } else { + // logger.warn("getPopulatedDocument(), pKeyValue is null for entityType = " + + // resultDescriptor.getEntityName()); + logger.error(EntityEventPolicyMsgs.PRIMARY_KEY_NULL_FOR_ENTITY_TYPE, + resultDescriptor.getEntityName()); + } + } + + final String primaryCompositeKeyValue = RouterServiceUtil.concatArray(primaryKeyValues, "/"); + d.setEntityPrimaryKeyValue(primaryCompositeKeyValue); + final String primaryCompositeKeyName = RouterServiceUtil.concatArray(primaryKeyNames, "/"); + d.setEntityPrimaryKeyName(primaryCompositeKeyName); + + final List searchTagFields = resultDescriptor.getSearchableAttributes(); + + /* + * Based on configuration, use the configured field names for this entity-Type to build a + * multi-value collection of search tags for elastic search entity search criteria. + */ + + + for (String searchTagField : searchTagFields) { + String searchTagValue = RouterServiceUtil.getNodeFieldAsText(entityNode, searchTagField); + if (searchTagValue != null && !searchTagValue.isEmpty()) { + d.addSearchTagWithKey(searchTagValue, searchTagField); + } + } + + return d; + } + + + + // put this here until we find a better spot + /** + * Helper utility to concatenate substrings of a URI together to form a proper URI. + * + * @param suburis the list of substrings to concatenate together + * @return the concatenated list of substrings + */ + private static String concatSubUri(String... suburis) { + String finalUri = ""; + + for (String suburi : suburis) { + + if (suburi != null) { + // Remove any leading / since we only want to append / + suburi = suburi.replaceFirst("^/*", ""); + + // Add a trailing / if one isn't already there + finalUri += suburi.endsWith("/") ? suburi : suburi + "/"; + } + } + + return finalUri; + } + + + + /** + * Perform create, read, update or delete (CRUD) operation on search engine's suggestive search + * index + * + * @param eventEntity Entity/data to use in operation + * @param action The operation to perform + */ + protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action, + String index) { + try { + + Map> headers = new HashMap<>(); + headers.put(Headers.FROM_APP_ID, Arrays.asList("DataLayer")); + headers.put(Headers.TRANSACTION_ID, Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID))); + + String entityId = eventEntity.getId(); + + if ((action.equalsIgnoreCase(ACTION_CREATE) && entityId != null) + || action.equalsIgnoreCase(ACTION_UPDATE)) { + + // Run the GET to retrieve the ETAG from the search service + OperationResult storedEntity = searchAgent.getDocument(index, entityId); + + if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) { + List etag = storedEntity.getHeaders().get(Headers.ETAG); + + if (etag != null && !etag.isEmpty()) { + headers.put(Headers.IF_MATCH, etag); + } else { + logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId); + } + } + + // Write the entity to the search service. + // PUT + searchAgent.putDocument(index, entityId, eventEntity.getAsJson(), headers); + } else if (action.equalsIgnoreCase(ACTION_CREATE)) { + // Write the entry to the search service. + searchAgent.postDocument(index, eventEntity.getAsJson(), headers); + + } else if (action.equalsIgnoreCase(ACTION_DELETE)) { + // Run the GET to retrieve the ETAG from the search service + OperationResult storedEntity = searchAgent.getDocument(index, entityId); + + if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) { + List etag = storedEntity.getHeaders().get(Headers.ETAG); + + if (etag != null && !etag.isEmpty()) { + headers.put(Headers.IF_MATCH, etag); + } else { + logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId); + } + + searchAgent.deleteDocument(index, eventEntity.getId(), headers); + } else { + logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId); + } + } else { + logger.error(EntityEventPolicyMsgs.ENTITY_OPERATION_NOT_SUPPORTED, action); + } + } catch (IOException e) { + logger.error(EntityEventPolicyMsgs.FAILED_TO_UPDATE_ENTITY_IN_DOCSTORE, eventEntity.getId(), + action); + } + } +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java b/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java index db68c21..1d447c9 100644 --- a/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java +++ b/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java @@ -901,7 +901,7 @@ public class EntityEventPolicy implements Processor { headers.put(Headers.IF_MATCH, etag); } else { logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, - entitySearchIndex, entityId); + entitySearchIndex, entityId); } ArrayList sourceObject = new ArrayList<>(); diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessor.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessor.java new file mode 100644 index 0000000..76fce7b --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessor.java @@ -0,0 +1,117 @@ +/** + * ============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.datarouter.policy; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +import org.apache.camel.Exchange; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.onap.aai.datarouter.entity.SpikeAggregationEntity; +import org.onap.aai.datarouter.entity.SpikeEventVertex; +import org.onap.aai.datarouter.logging.EntityEventPolicyMsgs; + +import com.fasterxml.jackson.databind.JsonNode; + + +public class SpikeAggregateGenericVnfProcessor extends AbstractSpikeEntityEventProcessor { + + public static final String additionalInfo = "Response of SpikeEntityEventPolicy"; + + /** Agent for communicating with the Search Service. */ + + public SpikeAggregateGenericVnfProcessor(SpikeEventPolicyConfig config) + throws FileNotFoundException { + super(config); + } + + @Override + protected void startup() { + // Create the indexes in the search service if they do not already exist. + searchAgent.createSearchIndex(searchIndexName, searchIndexSchema, createIndexUrl); + logger.info(EntityEventPolicyMsgs.ENTITY_EVENT_POLICY_REGISTERED); + } + + @Override + public void process(Exchange exchange) throws Exception { + + long startTime = System.currentTimeMillis(); + String uebPayload = getExchangeBody(exchange); + if (uebPayload == null) { + return; + } + JsonNode uebAsJson = null; + try { + uebAsJson = mapper.readTree(uebPayload); + } catch (IOException e) { + returnWithError(exchange, uebPayload, "Invalid Payload"); + return; + } + + String action = getSpikeEventAction(exchange, uebPayload); + if (action == null) { + return; + } + SpikeEventVertex eventVertex = populateEventVertex(exchange, uebPayload); + if (eventVertex == null) { + return; + } + String entityType = getEntityType(exchange, eventVertex, uebPayload); + if (entityType == null) { + return; + } + String entityLink = getEntityLink(exchange, eventVertex, uebPayload); + if (entityLink == null) { + return; + } + DynamicJAXBContext oxmJaxbContext = readOxm(exchange, uebPayload); + if (oxmJaxbContext == null) { + return; + } + String oxmEntityType = getOxmEntityType(entityType); + List searchableAttr = getSearchableAttibutes(oxmJaxbContext, oxmEntityType, entityType, uebPayload, + exchange); + if (searchableAttr == null) { + return; + } + + + // log the fact that all data are in good shape + logger.info(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE, action, entityType); + logger.debug(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_VERBOSE, action, entityType, + uebPayload); + + SpikeAggregationEntity spikeAgregationEntity = new SpikeAggregationEntity(); + spikeAgregationEntity.setLink(entityLink); + spikeAgregationEntity.deriveFields(uebAsJson); + handleSearchServiceOperation(spikeAgregationEntity, action, searchIndexName); + + long stopTime = System.currentTimeMillis(); + metricsLogger.info(EntityEventPolicyMsgs.OPERATION_RESULT_NO_ERRORS, PROCESS_SPIKE_EVENT, + String.valueOf(stopTime - startTime)); + setResponse(exchange, ResponseType.SUCCESS, additionalInfo); + return; + } + +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeAutosuggestIndexProcessor.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeAutosuggestIndexProcessor.java new file mode 100644 index 0000000..7c10fff --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeAutosuggestIndexProcessor.java @@ -0,0 +1,254 @@ +/** + * ============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.datarouter.policy; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.camel.Exchange; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.aai.datarouter.entity.OxmEntityDescriptor; +import org.onap.aai.datarouter.entity.SpikeEventVertex; +import org.onap.aai.datarouter.entity.SuggestionSearchEntity; +import org.onap.aai.datarouter.logging.EntityEventPolicyMsgs; +import org.onap.aai.datarouter.util.EntityOxmReferenceHelper; +import org.onap.aai.datarouter.util.SearchSuggestionPermutation; +import org.onap.aai.datarouter.util.Version; +import org.onap.aai.datarouter.util.VersionedOxmEntities; + +import com.fasterxml.jackson.databind.JsonNode; + + +public class SpikeAutosuggestIndexProcessor extends AbstractSpikeEntityEventProcessor { + + public static final String additionalInfo = "Response of SpikeEntityEventPolicy"; + + private final String EVENT_VERTEX = "vertex"; + + private String oxmVersion = null; + + /** Agent for communicating with the Search Service. */ + + public SpikeAutosuggestIndexProcessor(SpikeEventPolicyConfig config) + throws FileNotFoundException { + super(config); + parseLatestOxmVersion(); + } + + @Override + protected void startup() { + // Create the indexes in the search service if they do not already exist. + searchAgent.createSearchIndex(searchIndexName, searchIndexSchema, createIndexUrl); + logger.info(EntityEventPolicyMsgs.ENTITY_EVENT_POLICY_REGISTERED); + } + + @Override + public void process(Exchange exchange) throws Exception { + + long startTime = System.currentTimeMillis(); + String uebPayload = getExchangeBody(exchange); + if (uebPayload == null) { + return; + } + JsonNode uebAsJson = null; + try { + uebAsJson = mapper.readTree(uebPayload); + } catch (IOException e) { + returnWithError(exchange, uebPayload, "Invalid Payload"); + return; + } + + String action = getSpikeEventAction(exchange, uebPayload); + if (action == null) { + return; + } + JSONObject uebObjEntity = getUebContentAsJson(uebPayload, EVENT_VERTEX); + if (uebObjEntity == null) { + returnWithError(exchange, uebPayload, "Payload is missing " + EVENT_VERTEX); + return; + } + + SpikeEventVertex eventVertex = populateEventVertex(exchange, uebPayload); + if (eventVertex == null) { + return; + } + String entityType = getEntityType(exchange, eventVertex, uebPayload); + if (entityType == null) { + return; + } + String entityLink = getEntityLink(exchange, eventVertex, uebPayload); + if (entityLink == null) { + return; + } + DynamicJAXBContext oxmJaxbContext = readOxm(exchange, uebPayload); + if (oxmJaxbContext == null) { + return; + } + String oxmEntityType = getOxmEntityType(entityType); + List searchableAttr = getSearchableAttibutes(oxmJaxbContext, oxmEntityType, entityType, uebPayload, + exchange); + if (searchableAttr == null) { + return; + } + + // log the fact that all data are in good shape + logger.info(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE, action, entityType); + logger.debug(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_VERBOSE, action, entityType, + uebPayload); + + + /* + * Use the versioned OXM Entity class to get access to cross-entity reference helper collections + */ + VersionedOxmEntities oxmEntities = + EntityOxmReferenceHelper.getInstance().getVersionedOxmEntities(Version.valueOf(oxmVersion)); + + /* + * Process for autosuggestable entities + */ + if (oxmEntities != null) { + Map rootDescriptor = + oxmEntities.getSuggestableEntityDescriptors(); + if (!rootDescriptor.isEmpty()) { + List suggestibleAttrInPayload = new ArrayList<>(); + List suggestibleAttrInOxm = extractSuggestableAttr(oxmEntities, entityType); + if (suggestibleAttrInOxm != null) { + for (String attr: suggestibleAttrInOxm){ + if ( uebAsJson.get("vertex").get("properties").has(attr) ){ + suggestibleAttrInPayload.add(attr); + } + } + } + + if (suggestibleAttrInPayload.isEmpty()) { + return; + } + List suggestionAliases = extractAliasForSuggestableEntity(oxmEntities, entityType); + + /* + * It was decided to silently ignore DELETE requests for resources we don't allow to be + * deleted. e.g. auto-suggestion deletion is not allowed while aggregation deletion is. + */ + if (!ACTION_DELETE.equalsIgnoreCase(action)) { + List> listOfValidPowerSetElements = + SearchSuggestionPermutation.getNonEmptyUniqueLists(suggestibleAttrInPayload); + + // Now we have a list containing the power-set (minus empty element) for the status that are + // available in the payload. Try inserting a document for every combination. + for (ArrayList list : listOfValidPowerSetElements) { + SuggestionSearchEntity suggestionSearchEntity = new SuggestionSearchEntity(); + suggestionSearchEntity.setEntityType(entityType); + suggestionSearchEntity.setSuggestableAttr(list); + suggestionSearchEntity.setEntityTypeAliases(suggestionAliases); + suggestionSearchEntity.setFilterBasedPayloadFromResponse(uebAsJson.get("vertex").get("properties"), + suggestibleAttrInOxm, list); + suggestionSearchEntity.setSuggestionInputPermutations( + suggestionSearchEntity.generateSuggestionInputPermutations()); + + if (suggestionSearchEntity.isSuggestableDoc()) { + try { + suggestionSearchEntity.generateSearchSuggestionDisplayStringAndId(); + } catch (NoSuchAlgorithmException e) { + logger.error(EntityEventPolicyMsgs.DISCARD_UPDATING_SEARCH_SUGGESTION_DATA, + "Cannot create unique SHA digest for search suggestion data. Exception: " + + e.getLocalizedMessage()); + } + + handleSearchServiceOperation(suggestionSearchEntity, action, searchIndexName); + } + } + } + } + } + long stopTime = System.currentTimeMillis(); + metricsLogger.info(EntityEventPolicyMsgs.OPERATION_RESULT_NO_ERRORS, PROCESS_SPIKE_EVENT, + String.valueOf(stopTime - startTime)); + setResponse(exchange, ResponseType.SUCCESS, additionalInfo); + return; + } + + public List extractSuggestableAttr(VersionedOxmEntities oxmEntities, String entityType) { + // Extract suggestable attributeshandleTopographicalData + Map rootDescriptor = oxmEntities.getSuggestableEntityDescriptors(); + + if (rootDescriptor == null) { + return Collections.emptyList(); + } + + OxmEntityDescriptor desc = rootDescriptor.get(entityType); + + if (desc == null) { + return Collections.emptyList(); + } + + return desc.getSuggestableAttributes(); + } + + + public List extractAliasForSuggestableEntity(VersionedOxmEntities oxmEntities, + String entityType) { + + // Extract alias + Map rootDescriptor = oxmEntities.getEntityAliasDescriptors(); + + if (rootDescriptor == null) { + return Collections.emptyList(); + } + + OxmEntityDescriptor desc = rootDescriptor.get(entityType); + return desc.getAlias(); + } + + private void parseLatestOxmVersion() { + int latestVersion = -1; + if (oxmVersionContextMap != null) { + Iterator it = oxmVersionContextMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + + String version = pair.getKey().toString(); + int versionNum = Integer.parseInt(version.substring(1, version.length())); + + if (versionNum > latestVersion) { + latestVersion = versionNum; + oxmVersion = pair.getKey().toString(); + } + + logger.info(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_FOUND, pair.getKey().toString()); + } + } else { + logger.error(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_MISSING, ""); + } + } + + + +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessor.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessor.java new file mode 100644 index 0000000..7f7bdd9 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessor.java @@ -0,0 +1,160 @@ +/** + * ============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.datarouter.policy; + +import java.io.FileNotFoundException; +import java.util.List; + +import org.apache.camel.Exchange; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.onap.aai.datarouter.entity.SpikeEventEntity; +import org.onap.aai.datarouter.entity.SpikeEventVertex; +import org.onap.aai.datarouter.logging.EntityEventPolicyMsgs; + + +public class SpikeEntitySearchProcessor extends AbstractSpikeEntityEventProcessor { + + public static final String additionalInfo = "Response of SpikeEntityEventPolicy"; + private static final String searchIndexSchema = ""; + + + + /** Agent for communicating with the Search Service. */ + + public SpikeEntitySearchProcessor(SpikeEventPolicyConfig config) + throws FileNotFoundException { + super(config); + + } + + @Override + protected void startup() { + // Create the indexes in the search service if they do not already exist. + searchAgent.createSearchIndex(searchIndexName, searchIndexSchema); + logger.info(EntityEventPolicyMsgs.ENTITY_EVENT_POLICY_REGISTERED); + } + + @Override + public void process(Exchange exchange) throws Exception { + + long startTime = System.currentTimeMillis(); + String uebPayload = getExchangeBody(exchange); + if (uebPayload == null) { + return; + } + + String action = getSpikeEventAction(exchange, uebPayload); + if (action == null) { + return; + } + SpikeEventVertex eventVertex = populateEventVertex(exchange, uebPayload); + if (eventVertex == null) { + return; + } + String entityType = getEntityType(exchange, eventVertex, uebPayload); + if (entityType == null) { + return; + } + String entityLink = getEntityLink(exchange, eventVertex, uebPayload); + if (entityLink == null) { + return; + } + DynamicJAXBContext oxmJaxbContext = readOxm(exchange, uebPayload); + if (oxmJaxbContext == null) { + return; + } + String oxmEntityType = getOxmEntityType(entityType); + List searchableAttr = getSearchableAttibutes(oxmJaxbContext, oxmEntityType, entityType, uebPayload, + exchange); + if (searchableAttr == null) { + return; + } + + // log the fact that all data are in good shape + logger.info(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE, action, entityType); + logger.debug(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_VERBOSE, action, entityType, + uebPayload); + + SpikeEventEntity spikeEventEntity = new SpikeEventEntity(); + spikeEventEntity.setEntityType(entityType); + spikeEventEntity.setLink(entityLink); + spikeEventEntity = populateSpikeEventEntity(exchange, spikeEventEntity, oxmJaxbContext, + entityType, action, uebPayload, oxmEntityType,searchableAttr); + if (spikeEventEntity == null) { + return; + } + + handleSearchServiceOperation(spikeEventEntity, action, searchIndexName); + long stopTime = System.currentTimeMillis(); + metricsLogger.info(EntityEventPolicyMsgs.OPERATION_RESULT_NO_ERRORS, PROCESS_SPIKE_EVENT, + String.valueOf(stopTime - startTime)); + setResponse(exchange, ResponseType.SUCCESS, additionalInfo); + return; + } + + /* + * This is not for this Scope. We get back to it later. (updateCerInEntity) private void + * updateSearchEntityWithCrossEntityReference(SpikeEventEntity spikeEventEntity) { try { + * Map> headers = new HashMap<>(); headers.put(Headers.FROM_APP_ID, + * Arrays.asList("Data Router")); headers.put(Headers.TRANSACTION_ID, + * Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID))); + * + * String entityId = spikeEventEntity.getId(); String jsonPayload; + * + * // Run the GET to retrieve the ETAG from the search service OperationResult storedEntity = + * searchAgent.getDocument(entitySearchIndex, entityId); + * + * if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) { /* NOTES: + * aaiEventEntity (ie the nested entity) may contain a subset of properties of the pre-existing + * object, so all we want to do is update the CER on the pre-existing object (if needed). + * + * + * List etag = storedEntity.getHeaders().get(Headers.ETAG); + * + * if (etag != null && !etag.isEmpty()) { headers.put(Headers.IF_MATCH, etag); } else { + * logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, entitySearchIndex, entityId); } + * + * ArrayList sourceObject = new ArrayList<>(); + * NodeUtils.extractObjectsByKey(NodeUtils.convertJsonStrToJsonNode(storedEntity.getResult()), + * "content", sourceObject); + * + * if (!sourceObject.isEmpty()) { JsonNode node = sourceObject.get(0); final String sourceCer = + * NodeUtils.extractFieldValueFromObject(node, "crossEntityReferenceValues"); String newCer = + * spikeEventEntity.getCrossReferenceEntityValues(); boolean hasNewCer = true; if (sourceCer != + * null && sourceCer.length() > 0) { // already has CER if (!sourceCer.contains(newCer)) {// don't + * re-add newCer = sourceCer + ";" + newCer; } else { hasNewCer = false; } } + * + * if (hasNewCer) { // Do the PUT with new CER ((ObjectNode) + * node).put("crossEntityReferenceValues", newCer); jsonPayload = + * NodeUtils.convertObjectToJson(node, false); searchAgent.putDocument(entitySearchIndex, + * entityId, jsonPayload, headers); } } } else { + * + * if (storedEntity.getResultCode() == 404) { // entity not found, so attempt to do a PUT + * searchAgent.putDocument(entitySearchIndex, entityId, spikeEventEntity.getAsJson(), headers); } + * else { logger.error(EntityEventPolicyMsgs.FAILED_TO_UPDATE_ENTITY_IN_DOCSTORE, + * spikeEventEntity.getId(), "SYNC_ENTITY"); } } } catch (IOException e) { + * logger.error(EntityEventPolicyMsgs.FAILED_TO_UPDATE_ENTITY_IN_DOCSTORE, + * spikeEventEntity.getId(), "SYNC_ENTITY"); } } + */ + +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfig.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfig.java new file mode 100644 index 0000000..55db200 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfig.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.datarouter.policy; + +public class SpikeEventPolicyConfig { + + private String sourceDomain; + private String searchBaseUrl; + private String searchEndpoint; + private String searchEndpointDocuments; + private String searchCertName; + private String searchKeystorePwd; + private String searchKeystore; + + + public String getSourceDomain() { + return sourceDomain; + } + + public void setSourceDomain(String sourceDomain) { + this.sourceDomain = sourceDomain; + } + + public String getSearchBaseUrl() { + return searchBaseUrl; + } + + public void setSearchBaseUrl(String searchBaseUrl) { + this.searchBaseUrl = searchBaseUrl; + } + + public String getSearchEndpoint() { + return searchEndpoint; + } + + public void setSearchEndpoint(String searchEndpoint) { + this.searchEndpoint = searchEndpoint; + } + + public String getSearchEndpointDocuments() { + return searchEndpointDocuments; + } + + public void setSearchEndpointDocuments(String searchEndpointDocuments) { + this.searchEndpointDocuments = searchEndpointDocuments; + } + + + public String getSearchCertName() { + return searchCertName; + } + + public void setSearchCertName(String searchCertName) { + this.searchCertName = searchCertName; + } + + public String getSearchKeystore() { + return searchKeystore; + } + + public void setSearchKeystore(String searchKeystore) { + this.searchKeystore = searchKeystore; + } + + public String getSearchKeystorePwd() { + return searchKeystorePwd; + } + + public void setSearchKeystorePwd(String searchKeystorePwd) { + this.searchKeystorePwd = searchKeystorePwd; + } +} diff --git a/src/main/java/org/onap/aai/datarouter/util/SearchServiceAgent.java b/src/main/java/org/onap/aai/datarouter/util/SearchServiceAgent.java index fe1df3b..42861b4 100644 --- a/src/main/java/org/onap/aai/datarouter/util/SearchServiceAgent.java +++ b/src/main/java/org/onap/aai/datarouter/util/SearchServiceAgent.java @@ -127,6 +127,14 @@ public class SearchServiceAgent { createIndex(index, schemaLocation); } + public void createSearchIndex(String index, String schemaLocation, String endUrl) { + + // Create a mapping of the index name to schema location + indexSchemaMapping.put(index, schemaLocation); + + // Now, create the index. + createIndex(index, schemaLocation, endUrl); + } /** * This method performs the actual work of creating a search index. @@ -160,6 +168,30 @@ public class SearchServiceAgent { } } + private void createIndex(String index, String schemaLocation, String endUrl) { + + logger.debug("Creating search index, index name: = " + index + ", schemaLocation = " + schemaLocation); + + MultivaluedMap headers = new MultivaluedMapImpl(); + headers.put("Accept", Arrays.asList("application/json")); + headers.put(Headers.FROM_APP_ID, Arrays.asList("DL")); + headers.put(Headers.TRANSACTION_ID, Arrays.asList(UUID.randomUUID().toString())); + + String url = concatSubUri(searchUrl, endUrl, index); + try { + + OperationResult result = searchClient.put(url, loadFileData(schemaLocation), headers, + MediaType.APPLICATION_JSON_TYPE, null); + if (!HttpUtil.isHttpResponseClassSuccess(result.getResultCode())) { + logger.error(DataRouterMsgs.FAIL_TO_CREATE_SEARCH_INDEX, index, result.getFailureCause()); + } else { + logger.info(DataRouterMsgs.SEARCH_INDEX_CREATE_SUCCESS, index); + } + + } catch (Exception e) { + logger.error(DataRouterMsgs.FAIL_TO_CREATE_SEARCH_INDEX, index, e.getLocalizedMessage()); + } + } /** * Retrieves a document from the search service. diff --git a/src/main/resources/aggregatevnf_schema.json b/src/main/resources/aggregatevnf_schema.json new file mode 100644 index 0000000..03d5627 --- /dev/null +++ b/src/main/resources/aggregatevnf_schema.json @@ -0,0 +1,17 @@ +{ + "mappings": { + "default": { + "dynamic_templates": [{ + "strings": { + "match_mapping_type": "string", + "match": "*", + "mapping": { + "type": "string", + "index": "not_analyzed" + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/autosuggest_schema.json b/src/main/resources/autosuggest_schema.json new file mode 100644 index 0000000..99ac031 --- /dev/null +++ b/src/main/resources/autosuggest_schema.json @@ -0,0 +1,31 @@ +{ + "settings": { + "analysis": { + "filter": { + "eng_stop": { + "type": "stop", + "stopwords": "_english_" + } + }, + "analyzer": { + "custom_analyzer": { + "type": "custom", + "tokenizer": "standard", + "filter": ["lowercase", "asciifolding", "eng_stop"] + } + } + } + }, + "mappings": { + "default": { + "properties": { + "entity_suggest": { + "type": "completion", + "payloads": true, + "analyzer": "custom_analyzer", + "preserve_position_increments": false + } + } + } + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorStubbed.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorStubbed.java new file mode 100644 index 0000000..5bd35f6 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorStubbed.java @@ -0,0 +1,34 @@ +package org.onap.aai.datarouter.policy; + +import java.io.FileNotFoundException; + +import org.onap.aai.datarouter.entity.DocumentStoreDataEntity; + +public class SpikeAggregateGenericVnfProcessorStubbed extends SpikeAggregateGenericVnfProcessor { + + + public SpikeAggregateGenericVnfProcessorStubbed(SpikeEventPolicyConfig config) throws FileNotFoundException { + super(config); + + } + + protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action, String index) { + //Stub out the actual call to Search Data service and instead store/update documents in memory + try { + switch (action.toLowerCase()) { + case "create": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "update": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "delete": + InMemorySearchDatastore.remove(eventEntity.getId()); // they are executed if variable == c1 + break; + default: + break; + } + } catch (Exception ex) { + } + } +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorTest.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorTest.java new file mode 100644 index 0000000..d1c01af --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorTest.java @@ -0,0 +1,111 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.datarouter.policy; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.datarouter.util.NodeUtils; +import org.onap.aai.datarouter.util.SearchServiceAgent; +import org.powermock.api.mockito.PowerMockito; + + + +public class SpikeAggregateGenericVnfProcessorTest { + SpikeAggregateGenericVnfProcessor policy; + String eventJson; + + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + SpikeEventPolicyConfig config = PowerMockito.mock(SpikeEventPolicyConfig.class); + PowerMockito.when(config.getSearchKeystorePwd()).thenReturn("password"); + PowerMockito.when(config.getSourceDomain()).thenReturn("JUNIT"); + + + SearchServiceAgent searchServiceAgent = PowerMockito.mock(SearchServiceAgent.class); + PowerMockito.whenNew(SearchServiceAgent.class).withAnyArguments() + .thenReturn(searchServiceAgent); + + + policy = new SpikeAggregateGenericVnfProcessorStubbed(config); + FileInputStream event = new FileInputStream(new File("src/test/resources/spike_event.json")); + eventJson = IOUtils.toString(event, "UTF-8"); + + } + + @Test + public void testProcess_success() throws Exception { + policy.process(getExchangeEvent("12345", "create", "generic-vnf")); + policy.process(getExchangeEvent("23456", "create", "generic-vnf")); + + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/12345"))); + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/23456"))); + + + policy.process(getExchangeEvent("23456", "delete", "generic-vnf")); + assertNull(InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("23456"))); + } + @Test + public void testProcess_fail() throws Exception { + policy.process(getExchangeEvent("666666", "create", "NotValid")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("NotValid/666666"))); + + policy.process(getExchangeEvent("", "create", "generic-vnf")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/"))); + + } + + + private Exchange getExchangeEvent(String key, String action, String type) { + Object obj = eventJson.replace("$KEY", key).replace("$ACTION", action).replace("$TYPE", type); + Exchange exchange = PowerMockito.mock(Exchange.class); + Message inMessage = PowerMockito.mock(Message.class); + Message outMessage = PowerMockito.mock(Message.class); + PowerMockito.when(exchange.getIn()).thenReturn(inMessage); + PowerMockito.when(inMessage.getBody()).thenReturn(obj); + + PowerMockito.when(exchange.getOut()).thenReturn(outMessage); + PowerMockito.doNothing().when(outMessage).setBody(anyObject()); + PowerMockito.doNothing().when(outMessage).setHeader(anyString(), anyObject()); + + return exchange; + + } + + + +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorStubbed.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorStubbed.java new file mode 100644 index 0000000..cf3b255 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorStubbed.java @@ -0,0 +1,34 @@ +package org.onap.aai.datarouter.policy; + +import java.io.FileNotFoundException; + +import org.onap.aai.datarouter.entity.DocumentStoreDataEntity; + +public class SpikeAutosuggestProcessorStubbed extends SpikeAutosuggestIndexProcessor { + + + public SpikeAutosuggestProcessorStubbed(SpikeEventPolicyConfig config) throws FileNotFoundException { + super(config); + + } + + protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action, String index) { + //Stub out the actual call to Search Data service and instead store/update documents in memory + try { + switch (action.toLowerCase()) { + case "create": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "update": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "delete": + InMemorySearchDatastore.remove(eventEntity.getId()); // they are executed if variable == c1 + break; + default: + break; + } + } catch (Exception ex) { + } + } +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorTest.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorTest.java new file mode 100644 index 0000000..f3c72f1 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorTest.java @@ -0,0 +1,89 @@ +package org.onap.aai.datarouter.policy; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.datarouter.util.NodeUtils; +import org.onap.aai.datarouter.util.SearchServiceAgent; +import org.powermock.api.mockito.PowerMockito; + + + +public class SpikeAutosuggestProcessorTest { + SpikeAutosuggestIndexProcessor policy; + String eventJson; + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + SpikeEventPolicyConfig config = PowerMockito.mock(SpikeEventPolicyConfig.class); + PowerMockito.when(config.getSearchKeystorePwd()).thenReturn("password"); + PowerMockito.when(config.getSourceDomain()).thenReturn("JUNIT"); + + + SearchServiceAgent searchServiceAgent = PowerMockito.mock(SearchServiceAgent.class); + PowerMockito.whenNew(SearchServiceAgent.class).withAnyArguments() + .thenReturn(searchServiceAgent); + + + policy = new SpikeAutosuggestProcessorStubbed(config); + FileInputStream event = new FileInputStream(new File("src/test/resources/spike_event.json")); + eventJson = IOUtils.toString(event, "UTF-8"); + + } + + @Test + public void testProcess_success() throws Exception { + policy.process(getExchangeEvent("77777", "create", "generic-vnf")); + + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("junk and Running VNFs"))); + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("junk VNFs"))); + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("Running VNFs"))); + + + } + @Test + public void testProcess_fail() throws Exception { + policy.process(getExchangeEvent("666666", "create", "NotValid")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("NotValid/666666"))); + + policy.process(getExchangeEvent("", "create", "generic-vnf")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/"))); + + } + + + private Exchange getExchangeEvent(String key, String action, String type) { + Object obj = eventJson.replace("$KEY", key).replace("$ACTION", action).replace("$TYPE", type); + Exchange exchange = PowerMockito.mock(Exchange.class); + Message inMessage = PowerMockito.mock(Message.class); + Message outMessage = PowerMockito.mock(Message.class); + PowerMockito.when(exchange.getIn()).thenReturn(inMessage); + PowerMockito.when(inMessage.getBody()).thenReturn(obj); + + PowerMockito.when(exchange.getOut()).thenReturn(outMessage); + PowerMockito.doNothing().when(outMessage).setBody(anyObject()); + PowerMockito.doNothing().when(outMessage).setHeader(anyString(), anyObject()); + + return exchange; + + } + + + +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorStubbed.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorStubbed.java new file mode 100644 index 0000000..100ff0a --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorStubbed.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.datarouter.policy; + +import java.io.FileNotFoundException; + +import org.onap.aai.datarouter.entity.DocumentStoreDataEntity; + +public class SpikeEntitySearchProcessorStubbed extends SpikeEntitySearchProcessor { + + + public SpikeEntitySearchProcessorStubbed(SpikeEventPolicyConfig config) throws FileNotFoundException { + super(config); + + } + + protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action, String index) { + //Stub out the actual call to Search Data service and instead store/update documents in memory + try { + switch (action.toLowerCase()) { + case "create": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "update": + InMemorySearchDatastore.put(eventEntity.getId(), eventEntity.getAsJson()); // they are executed if variable == c1 + break; + case "delete": + InMemorySearchDatastore.remove(eventEntity.getId()); // they are executed if variable == c1 + break; + default: + break; + } + } catch (Exception ex) { + } + } +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorTest.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorTest.java new file mode 100644 index 0000000..08518b1 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorTest.java @@ -0,0 +1,117 @@ +package org.onap.aai.datarouter.policy; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.datarouter.util.NodeUtils; +import org.onap.aai.datarouter.util.SearchServiceAgent; +import org.powermock.api.mockito.PowerMockito; + + + +public class SpikeEntitySearchProcessorTest { + SpikeEntitySearchProcessor policy; + String eventJson; + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + SpikeEventPolicyConfig config = PowerMockito.mock(SpikeEventPolicyConfig.class); + PowerMockito.when(config.getSearchKeystorePwd()).thenReturn("password"); + PowerMockito.when(config.getSourceDomain()).thenReturn("JUNIT"); + + + SearchServiceAgent searchServiceAgent = PowerMockito.mock(SearchServiceAgent.class); + PowerMockito.whenNew(SearchServiceAgent.class).withAnyArguments() + .thenReturn(searchServiceAgent); + + + policy = new SpikeEntitySearchProcessorStubbed(config); + FileInputStream event = new FileInputStream(new File("src/test/resources/spike_event.json")); + eventJson = IOUtils.toString(event, "UTF-8"); + + } + + @Test + public void testProcess_success() throws Exception { + policy.process(getExchangeEvent("12345", "create", "generic-vnf")); + policy.process(getExchangeEvent("23456", "create", "generic-vnf")); + + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/12345"))); + assertNotNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/23456"))); + + + policy.process(getExchangeEvent("23456", "delete", "generic-vnf")); + assertNull(InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/23456"))); + + policy.process(getExchangeEvent("333333", "", "generic-vnf")); + assertNull(InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/333333"))); + } + @Test + public void testProcess_fail() throws Exception { + policy.process(getExchangeEvent("xxxxx", "create", "NotValid")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("NotValid/xxxxx"))); + + policy.process(getExchangeEvent("", "create", "generic-vnf")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("generic-vnf/"))); + + policy.process(getExchangeEvent("yyyy", "create", "")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("/yyyy"))); + policy.process(getExchangeEvent("", "create", "")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("/"))); + } + @Test + public void testProcess_null() throws Exception { + policy.process(getExchangeEvent()); + } + + private Exchange getExchangeEvent(String key, String action, String type) { + Object obj = eventJson.replace("$KEY", key).replace("$ACTION", action).replace("$TYPE", type); + Exchange exchange = PowerMockito.mock(Exchange.class); + Message inMessage = PowerMockito.mock(Message.class); + Message outMessage = PowerMockito.mock(Message.class); + PowerMockito.when(exchange.getIn()).thenReturn(inMessage); + PowerMockito.when(inMessage.getBody()).thenReturn(obj); + + PowerMockito.when(exchange.getOut()).thenReturn(outMessage); + PowerMockito.doNothing().when(outMessage).setBody(anyObject()); + PowerMockito.doNothing().when(outMessage).setHeader(anyString(), anyObject()); + + return exchange; + + } + + private Exchange getExchangeEvent() { + Object obj = ""; + Exchange exchange = PowerMockito.mock(Exchange.class); + Message inMessage = PowerMockito.mock(Message.class); + Message outMessage = PowerMockito.mock(Message.class); + PowerMockito.when(exchange.getIn()).thenReturn(inMessage); + PowerMockito.when(inMessage.getBody()).thenReturn(obj); + + PowerMockito.when(exchange.getOut()).thenReturn(outMessage); + PowerMockito.doNothing().when(outMessage).setBody(anyObject()); + PowerMockito.doNothing().when(outMessage).setHeader(anyString(), anyObject()); + + return exchange; + + } + + +} diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfigTest.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfigTest.java new file mode 100644 index 0000000..831695e --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfigTest.java @@ -0,0 +1,59 @@ +/** + * ============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.datarouter.policy; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SpikeEventPolicyConfigTest { + + @Test + public void testAllMethods() { + SpikeEventPolicyConfig eConfig = new SpikeEventPolicyConfig(); + eConfig.setSourceDomain("source-domain"); + Assert.assertEquals(eConfig.getSourceDomain(),"source-domain"); + + eConfig.setSearchBaseUrl("http://base-url"); + Assert.assertEquals(eConfig.getSearchBaseUrl(),"http://base-url"); + + eConfig.setSearchEndpoint("end-point"); + Assert.assertEquals(eConfig.getSearchEndpoint(),"end-point"); + + eConfig.setSearchEndpointDocuments("end-document"); + Assert.assertEquals(eConfig.getSearchEndpointDocuments(),"end-document"); + + + eConfig.setSearchCertName("cert-name"); + Assert.assertEquals(eConfig.getSearchCertName(),"cert-name"); + + eConfig.setSearchKeystore("key-store"); + Assert.assertEquals(eConfig.getSearchKeystore(),"key-store"); + + eConfig.setSearchKeystorePwd("key-store-pass"); + Assert.assertEquals(eConfig.getSearchKeystorePwd(),"key-store-pass"); + + } + +} \ No newline at end of file -- 2.16.6