From: Attaranasl, Salma (sa669h) Date: Thu, 8 Mar 2018 16:58:02 +0000 (-0500) Subject: added Spike event Policy X-Git-Tag: v1.2.0~18 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=aai%2Fdata-router.git;a=commitdiff_plain;h=4c416b0e0059370184f77991481f61d779eccd80 added Spike event Policy to read from Spike Event and save the index on Search Data removed the extra header on a file: Issue-ID: AAI-846 Change-Id: I5fa66b5c6b0b6b2f645315221fbf2eb1461c5ca7 Signed-off-by: Attaranasl, Salma --- diff --git a/src/main/java/org/onap/aai/datarouter/entity/SpikeEventEntity.java b/src/main/java/org/onap/aai/datarouter/entity/SpikeEventEntity.java new file mode 100644 index 0000000..2b13436 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/entity/SpikeEventEntity.java @@ -0,0 +1,260 @@ +/* +* ============LICENSE_START======================================================= +* DataRouter +* ================================================================================ +* 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.datarouter.entity; + +import java.io.IOException; +import java.io.Serializable; +import java.security.NoSuchAlgorithmException; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; + +import javax.json.Json; +import javax.json.JsonObject; + +import org.onap.aai.datarouter.util.NodeUtils; + +/** + * Note: SpikeEventEntity is a port forward of IndexDocument Has been renamed here to move forward + * with abstraction of document store technology. + */ +public class SpikeEventEntity implements DocumentStoreDataEntity, Serializable { + + private static final long serialVersionUID = -5188479658230319058L; + + protected String entityType; + protected String entityPrimaryKeyName; + protected String entityPrimaryKeyValue; + protected ArrayList searchTagCollection = new ArrayList<>(); + protected ArrayList searchTagIdCollection = new ArrayList<>(); + protected ArrayList crossEntityReferenceCollection = new ArrayList<>(); + protected String lastmodTimestamp; + protected String link; + + private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + /* + * Generated fields, leave the settings for junit overrides + */ + + // generated, SHA-256 digest + protected String id; + + /* + * generated based on searchTagCollection values + */ + protected String searchTags; + protected String searchTagIds; + protected String crossReferenceEntityValues; + + + + private static String concatArray(List list, char delimiter) { + + if (list == null || list.isEmpty()) { + return ""; + } + + StringBuilder result = new StringBuilder(64); + + boolean firstValue = true; + + for (String item : list) { + + if (firstValue) { + result.append(item); + firstValue = false; + } else { + result.append(delimiter).append(item); + } + + } + + return result.toString(); + + } + + public SpikeEventEntity() { + SimpleDateFormat dateFormat = new SimpleDateFormat(TIMESTAMP_FORMAT); + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + String currentFormattedTimeStamp = dateFormat.format(timestamp); + this.lastmodTimestamp = currentFormattedTimeStamp; + } + + public void deriveFields() throws NoSuchAlgorithmException { + this.id = NodeUtils.generateUniqueShaDigest(link); + this.searchTags = concatArray(searchTagCollection, ';'); + this.searchTagIds = concatArray(searchTagIdCollection, ';'); + this.crossReferenceEntityValues = concatArray(crossEntityReferenceCollection, ';'); + } + + + /* + * (non-Javadoc) + * + * @see org.onap.aai.datarouter.entity.SpikeEventEntity#getAsJson() + */ + @Override + public String getAsJson() throws IOException { + + JsonObject obj = Json.createObjectBuilder().add("entityType", entityType) + .add("entityPrimaryKeyValue", entityPrimaryKeyValue).add("searchTagIDs", searchTagIds) + .add("searchTags", searchTags).add("crossEntityReferenceValues", crossReferenceEntityValues) + .add("lastmodTimestamp", lastmodTimestamp).add("link", link).build(); + + return obj.toString(); + } + + + public void addSearchTagWithKey(String searchTag, String key) { + searchTagIdCollection.add(key); + searchTagCollection.add(searchTag); + } + + public void addCrossEntityReferenceValue(String crossEntityReferenceValue) { + if (!crossEntityReferenceCollection.contains(crossEntityReferenceValue)) { + crossEntityReferenceCollection.add(crossEntityReferenceValue); + } + } + + public String getEntityType() { + return entityType; + } + + public String getEntityPrimaryKeyName() { + return entityPrimaryKeyName; + } + + public String getEntityPrimaryKeyValue() { + return entityPrimaryKeyValue; + } + + + /* + * (non-Javadoc) + * + * @see org.onap.aai.datarouter.entity.SpikeEventEntity#getId() + */ + @Override + public String getId() { + return id; + } + + public ArrayList getSearchTagCollection() { + return searchTagCollection; + } + + public String getSearchTags() { + return searchTags; + } + + public String getSearchTagIDs() { + return searchTagIds; + } + + public void setSearchTagIDs(String searchTagIDs) { + this.searchTagIds = searchTagIDs; + } + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public void setId(String id) { + this.id = id; + } + + public void setSearchTagCollection(ArrayList searchTagCollection) { + this.searchTagCollection = searchTagCollection; + } + + public void setSearchTags(String searchTags) { + this.searchTags = searchTags; + } + + public ArrayList getSearchTagIdCollection() { + return searchTagIdCollection; + } + + public void setSearchTagIdCollection(ArrayList searchTagIdCollection) { + this.searchTagIdCollection = searchTagIdCollection; + } + + public String getLastmodTimestamp() { + return lastmodTimestamp; + } + + public void setLastmodTimestamp(String lastmodTimestamp) { + this.lastmodTimestamp = lastmodTimestamp; + } + + public void setEntityPrimaryKeyName(String entityPrimaryKeyName) { + this.entityPrimaryKeyName = entityPrimaryKeyName; + } + + public void setEntityPrimaryKeyValue(String entityPrimaryKeyValue) { + this.entityPrimaryKeyValue = entityPrimaryKeyValue; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + + + public String getCrossReferenceEntityValues() { + return crossReferenceEntityValues; + } + + public void setCrossReferenceEntityValues(String crossReferenceEntityValues) { + this.crossReferenceEntityValues = crossReferenceEntityValues; + } + + @Override + public String toString() { + return "SpikeEventEntity [" + (entityType != null ? "entityType=" + entityType + ", " : "") + + (entityPrimaryKeyName != null ? "entityPrimaryKeyName=" + entityPrimaryKeyName + ", " + : "") + + (entityPrimaryKeyValue != null ? "entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", " + : "") + + (searchTagCollection != null ? "searchTagCollection=" + searchTagCollection + ", " : "") + + (searchTagIdCollection != null ? "searchTagIDCollection=" + searchTagIdCollection + ", " + : "") + + (crossEntityReferenceCollection != null + ? "crossEntityReferenceCollection=" + crossEntityReferenceCollection + ", " : "") + + "lastmodTimestamp=" + lastmodTimestamp + ", " + (id != null ? "id=" + id + ", " : "") + + (searchTags != null ? "searchTags=" + searchTags + ", " : "") + + (searchTagIds != null ? "searchTagIDs=" + searchTagIds + ", " : "") + + (crossReferenceEntityValues != null + ? "crossReferenceEntityValues=" + crossReferenceEntityValues : "") + + "]"; + } + +} diff --git a/src/main/java/org/onap/aai/datarouter/entity/SpikeEventVertex.java b/src/main/java/org/onap/aai/datarouter/entity/SpikeEventVertex.java new file mode 100644 index 0000000..ab114ab --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/entity/SpikeEventVertex.java @@ -0,0 +1,72 @@ +/** + * ============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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * A convenience POJO for mapping the Vertex from a Spike Event. + * + * @author salmaA + */ + +@JsonIgnoreProperties(ignoreUnknown = true) +public class SpikeEventVertex { + + private String key; + + private String schemaVersion; + + private String type; + + + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getSchemaVersion() { + return schemaVersion; + } + + public void setSchemaVersion(String schemaVersion) { + this.schemaVersion = schemaVersion; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getEntityLink() { + return this.type + "/" + this.key; + } + +} diff --git a/src/main/java/org/onap/aai/datarouter/logging/EntityEventPolicyMsgs.java b/src/main/java/org/onap/aai/datarouter/logging/EntityEventPolicyMsgs.java index a32216b..aa64d3d 100644 --- a/src/main/java/org/onap/aai/datarouter/logging/EntityEventPolicyMsgs.java +++ b/src/main/java/org/onap/aai/datarouter/logging/EntityEventPolicyMsgs.java @@ -35,14 +35,14 @@ public enum EntityEventPolicyMsgs implements LogMessageEnum { * {0} = reason * {1} = Payload: */ - DISCARD_AAI_EVENT_VERBOSE, + DISCARD_EVENT_VERBOSE, /** * Discarding event. * Arguments: * {0} = Reason */ - DISCARD_AAI_EVENT_NONVERBOSE, + DISCARD_EVENT_NONVERBOSE, /** * OXM version: {0} is not supported. @@ -135,7 +135,7 @@ public enum EntityEventPolicyMsgs implements LogMessageEnum { * {1} = Entity Type * {2} = Payload */ - PROCESS_AAI_ENTITY_EVENT_POLICY_VERBOSE, + PROCESS_ENTITY_EVENT_POLICY_VERBOSE, /** * Processing AAI Entity Event Policy: @@ -143,7 +143,7 @@ public enum EntityEventPolicyMsgs implements LogMessageEnum { * {0} = Action * {1} = Entity Type */ - PROCESS_AAI_ENTITY_EVENT_POLICY_NONVERBOSE, + PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE, /** * Cross Entity Reference synchronization {0} 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 d081868..cf937bf 100644 --- a/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java +++ b/src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java @@ -204,8 +204,8 @@ public class EntityEventPolicy implements Processor { } public void returnWithError(Exchange exchange, String payload, String errorMsg){ - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, errorMsg); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, errorMsg, payload); + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, errorMsg); + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, errorMsg, payload); setResponse(exchange, ResponseType.FAILURE, additionalInfo); } @@ -244,9 +244,9 @@ public class EntityEventPolicy implements Processor { // Get src domain from header; discard event if not originated from same domain String payloadSrcDomain = eventHeader.getDomain(); if (payloadSrcDomain == null || !payloadSrcDomain.equalsIgnoreCase(this.srcDomain)) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Unrecognized source domain '" + payloadSrcDomain + "'", uebPayload); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Unrecognized source domain '" + payloadSrcDomain + "'"); setResponse(exchange, ResponseType.SUCCESS, additionalInfo); @@ -256,7 +256,7 @@ public class EntityEventPolicy implements Processor { DynamicJAXBContext oxmJaxbContext = loadOxmContext(oxmVersion.toLowerCase()); if (oxmJaxbContext == null) { logger.error(EntityEventPolicyMsgs.OXM_VERSION_NOT_SUPPORTED, oxmVersion); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, "OXM version mismatch", + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "OXM version mismatch", uebPayload); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -265,9 +265,9 @@ public class EntityEventPolicy implements Processor { String action = eventHeader.getAction(); if (action == null || !SUPPORTED_ACTIONS.contains(action.toLowerCase())) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Unrecognized action '" + action + "'", uebPayload); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Unrecognized action '" + action + "'"); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -276,9 +276,9 @@ public class EntityEventPolicy implements Processor { String entityType = eventHeader.getEntityType(); if (entityType == null) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload header missing entity type", uebPayload); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload header missing entity type"); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -287,9 +287,9 @@ public class EntityEventPolicy implements Processor { String topEntityType = eventHeader.getTopEntityType(); if (topEntityType == null) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload header missing top entity type", uebPayload); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload header top missing entity type"); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -298,9 +298,9 @@ public class EntityEventPolicy implements Processor { String entityLink = eventHeader.getEntityLink(); if (entityLink == null) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload header missing entity link", uebPayload); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload header missing entity link"); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -308,9 +308,9 @@ public class EntityEventPolicy implements Processor { } // log the fact that all data are in good shape - logger.info(EntityEventPolicyMsgs.PROCESS_AAI_ENTITY_EVENT_POLICY_NONVERBOSE, action, + logger.info(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE, action, entityType); - logger.debug(EntityEventPolicyMsgs.PROCESS_AAI_ENTITY_EVENT_POLICY_VERBOSE, action, entityType, + logger.debug(EntityEventPolicyMsgs.PROCESS_ENTITY_EVENT_POLICY_VERBOSE, action, entityType, uebPayload); @@ -324,9 +324,9 @@ public class EntityEventPolicy implements Processor { List searchableAttr = getOxmAttributes(uebPayload, oxmJaxbContext, oxmEntityType, entityType, "searchable"); if (searchableAttr == null) { - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Searchable attribute not found for payload entity type '" + entityType + "'"); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Searchable attribute not found for payload entity type '" + entityType + "'", uebPayload); @@ -338,9 +338,9 @@ public class EntityEventPolicy implements Processor { getEntityPrimaryKeyFieldName(oxmJaxbContext, uebPayload, oxmEntityType, entityType); String entityPrimaryKeyFieldValue = lookupValueUsingKey(uebPayload, entityPrimaryKeyFieldName); if (entityPrimaryKeyFieldValue == null || entityPrimaryKeyFieldValue.isEmpty()) { - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload missing primary key attribute"); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload missing primary key attribute", uebPayload); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -359,9 +359,9 @@ public class EntityEventPolicy implements Processor { aaiEventEntity.setLink(entityLink); if (!getSearchTags(aaiEventEntity, searchableAttr, uebPayload, action)) { - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload missing searchable attribute for entity type '" + entityType + "'"); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload missing searchable attribute for entity type '" + entityType + "'", uebPayload); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -373,9 +373,9 @@ public class EntityEventPolicy implements Processor { aaiEventEntity.deriveFields(); } catch (NoSuchAlgorithmException e) { - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest"); - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest", uebPayload); setResponse(exchange, ResponseType.FAILURE, additionalInfo); @@ -815,9 +815,9 @@ public class EntityEventPolicy implements Processor { try { uebJsonObj = new JSONObject(payload); } catch (JSONException e) { - logger.debug(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_VERBOSE, + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload has invalid JSON Format", payload.toString()); - logger.error(EntityEventPolicyMsgs.DISCARD_AAI_EVENT_NONVERBOSE, + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, "Payload has invalid JSON Format"); return null; } diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicy.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicy.java new file mode 100644 index 0000000..cef0b70 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicy.java @@ -0,0 +1,666 @@ +/** + * ============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.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.SpikeEventEntity; +import org.onap.aai.datarouter.entity.DocumentStoreDataEntity; +import org.onap.aai.datarouter.entity.SpikeEventVertex; +import org.onap.aai.datarouter.entity.OxmEntityDescriptor; +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 class SpikeEntityEventPolicy implements Processor { + + public static final String additionalInfo = "Response of SpikeEntityEventPolicy"; + private static final String entitySearchSchema = "entitysearch_schema.json"; + + private Collection externalOxmModelProcessors; + + + private final String ACTION_CREATE = "create"; + private final String EVENT_VERTEX = "vertex"; + private final static String ACTION_DELETE = "delete"; + private final String ACTION_UPDATE = "update"; + private final String PROCESS_SPIKE_EVENT = "Process Spike Event"; + private final String OPERATION_KEY = "operation"; + + + 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. */ + private SearchServiceAgent searchAgent = null; + private String entitySearchIndex; + private String srcDomain; + + private Logger logger; + private Logger metricsLogger; + + public enum ResponseType { + SUCCESS, PARTIAL_SUCCESS, FAILURE; + }; + + public SpikeEntityEventPolicy(SpikeEntityEventPolicyConfig config) throws FileNotFoundException { + LoggerFactory loggerFactoryInstance = LoggerFactory.getInstance(); + logger = loggerFactoryInstance.getLogger(SpikeEntityEventPolicy.class.getName()); + metricsLogger = loggerFactoryInstance.getMetricsLogger(SpikeEntityEventPolicy.class.getName()); + + + srcDomain = config.getSourceDomain(); + + // Populate the index names. + entitySearchIndex = config.getSearchEntitySearchIndex(); + + // Instantiate the agent that we will use for interacting with the Search Service. + searchAgent = new SearchServiceAgent(config.getSearchCertName(), config.getSearchKeystore(), + config.getSearchKeystorePwd(), + EntityEventPolicy.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(); + } + + 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, ""); + } + } + + public void startup() { + + // Create the indexes in the search service if they do not already exist. + searchAgent.createSearchIndex(entitySearchIndex, entitySearchSchema); + logger.info(EntityEventPolicyMsgs.ENTITY_EVENT_POLICY_REGISTERED); + } + + + /** + * Convert object to json. + * + * @param object the object + * @param pretty the pretty + * @return the string + * @throws JsonProcessingException the json processing exception + */ + public 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); + } + + public 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); + } + + public boolean isJSONValid(String test) { + try { + new JSONObject(test); + } catch (JSONException ex) { + return false; + } + return true; + } + + @Override + public void process(Exchange exchange) throws Exception { + + long startTime = System.currentTimeMillis(); + 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; + } + } + + + 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; + } + + // 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; + } + + SpikeEventVertex eventVertex = initializeSpikeEventVertex(spikeObjVertex.toString()); + + 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; + } + + + + 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; + } + + 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; + } + String entityLink = eventVertex.getEntityLink(); + if (entityLink == null || entityLink.isEmpty()) { + logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, + "Payload header missing entity link", uebPayload); + logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, + "Payload header missing entity link"); + + setResponse(exchange, ResponseType.FAILURE, additionalInfo); + 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); + + + // Process for building SpikeEventEntity object + String[] entityTypeArr = entityType.split("-"); + String oxmEntityType = ""; + for (String entityWord : entityTypeArr) { + oxmEntityType += entityWord.substring(0, 1).toUpperCase() + entityWord.substring(1); + } + + 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; + } + + 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; + } + 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; + } + + SpikeEventEntity spikeEventEntity = new SpikeEventEntity(); + + /* + * Use the OXM Model to determine the primary key field name based on the entity-type + */ + + spikeEventEntity.setEntityPrimaryKeyName(entityPrimaryKeyFieldName); + spikeEventEntity.setEntityPrimaryKeyValue(entityPrimaryKeyFieldValue); + spikeEventEntity.setEntityType(entityType); + spikeEventEntity.setLink(entityLink); + + 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; + } + + 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; + } + + + handleSearchServiceOperation(spikeEventEntity, action, entitySearchIndex); + + long stopTime = System.currentTimeMillis(); + metricsLogger.info(EntityEventPolicyMsgs.OPERATION_RESULT_NO_ERRORS, PROCESS_SPIKE_EVENT, + String.valueOf(stopTime - startTime)); + + setResponse(exchange, ResponseType.SUCCESS, additionalInfo); + return; + } + + + + private void setResponse(Exchange exchange, ResponseType responseType, String additionalInfo) { + + exchange.getOut().setHeader("ResponseType", responseType.toString()); + exchange.getOut().setBody(additionalInfo); + } + + + /* + * Load the UEB JSON payload, any errors would result to a failure case response. + */ + private 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; + } + + + 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; + } + + + /** + * 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 + * @param target Resource to perform the operation on + * @param allowDeleteEvent Allow delete operation to be performed on resource + */ + 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); + } + } + + + + // 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 + */ + public 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; + } +} diff --git a/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyConfig.java b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyConfig.java new file mode 100644 index 0000000..79ac3a3 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyConfig.java @@ -0,0 +1,99 @@ +/** + * ============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; + +public class SpikeEntityEventPolicyConfig { + + private String sourceDomain; + private String searchBaseUrl; + private String searchEndpoint; + private String searchEndpointDocuments; + private String searchEntitySearchIndex; + 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 getSearchEntitySearchIndex() { + return searchEntitySearchIndex; + } + + public void setSearchEntitySearchIndex(String searchEntitySearchIndex) { + this.searchEntitySearchIndex = searchEntitySearchIndex; + } + 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/resources/logging/EntityEventPolicyMsgs.properties b/src/main/resources/logging/EntityEventPolicyMsgs.properties index 85444c9..8debaae 100644 --- a/src/main/resources/logging/EntityEventPolicyMsgs.properties +++ b/src/main/resources/logging/EntityEventPolicyMsgs.properties @@ -21,11 +21,11 @@ ######################################################################## -DISCARD_AAI_EVENT_VERBOSE=\ +DISCARD_EVENT_VERBOSE=\ EEP0001E|\ Discarding event. Reason: {0}. Payload: {1} -DISCARD_AAI_EVENT_NONVERBOSE=\ +DISCARD_EVENT_NONVERBOSE=\ EEP0002E|\ Discarding event. Reason: {0} @@ -73,13 +73,13 @@ FAIL_TO_CREATE_SEARCH_INDEX=\ EEP012E|\ Failed to create Search index {0} due to: {1} -PROCESS_AAI_ENTITY_EVENT_POLICY_VERBOSE=\ +PROCESS_ENTITY_EVENT_POLICY_VERBOSE=\ EEP0001I|\ - Processing AAI Entity Event Policy: [Action: {0} Entity Type: {1}]. Payload: {2} + Processing Entity Event Policy: [Action: {0} Entity Type: {1}]. Payload: {2} -PROCESS_AAI_ENTITY_EVENT_POLICY_NONVERBOSE=\ +PROCESS_ENTITY_EVENT_POLICY_NONVERBOSE=\ EEP0002I|\ - Processing AAI Entity Event Policy: [Action: {0} Entity Type: {1}]. + Processing Entity Event Policy: [Action: {0} Entity Type: {1}]. CROSS_ENTITY_REFERENCE_SYNC=\ EEP0003I|\ diff --git a/src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyStubbed.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyStubbed.java new file mode 100644 index 0000000..7ba4f06 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyStubbed.java @@ -0,0 +1,34 @@ +package org.onap.aai.datarouter.policy; + +import java.io.FileNotFoundException; + +import org.onap.aai.datarouter.entity.DocumentStoreDataEntity; + +public class SpikeEntityEventPolicyStubbed extends SpikeEntityEventPolicy { + + + public SpikeEntityEventPolicyStubbed(SpikeEntityEventPolicyConfig 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/SpikeEntityEventPolicyTest.java b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyTest.java new file mode 100644 index 0000000..fd0d726 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyTest.java @@ -0,0 +1,90 @@ +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 SpikeEntityEventPolicyTest { + SpikeEntityEventPolicy policy; + String eventJson; + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + SpikeEntityEventPolicyConfig config = PowerMockito.mock(SpikeEntityEventPolicyConfig.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 SpikeEntityEventPolicyStubbed(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("12345", "create", "NotValid")); + assertNull( + InMemorySearchDatastore.get(NodeUtils.generateUniqueShaDigest("NotValid/12345"))); + + 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/resources/spike_event.json b/src/test/resources/spike_event.json new file mode 100644 index 0000000..0af1127 --- /dev/null +++ b/src/test/resources/spike_event.json @@ -0,0 +1,23 @@ +{"operation": "$ACTION", + "transaction-id": "ae83cf91-b73f-4759-b973-58c4192cea4c", + "timestamp": 1499460851548, + "vertex": { + "key": "$KEY", + "schema-version": "v10", + "type": "$TYPE", + "properties": { + "vnf-id": "GenericVNFIdBpCNtULbEw9", + "in-maint": "false", + "heat-stack-id": "GenericVNFIdBpCNtULbEw1-12345-678-", + "prov-status": "junk", + "equipment-role": "ASBG", + "ipv4-oam-address": "5.6.7.8", + "vnf-name": "GenericVNFIdBpCNtULbEw9", + "vnf-type": "asbg", + "is-closed-loop-disabled": "false", + "orchestration-status": "Running", + "aai-node-type": "generic-vnf" + } + }, + "result": "SUCCESS" +}