summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/onap/aai/datarouter/entity/SpikeEventEntity.java260
-rw-r--r--src/main/java/org/onap/aai/datarouter/entity/SpikeEventVertex.java72
-rw-r--r--src/main/java/org/onap/aai/datarouter/logging/EntityEventPolicyMsgs.java8
-rw-r--r--src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java50
-rw-r--r--src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicy.java666
-rw-r--r--src/main/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyConfig.java99
-rw-r--r--src/main/resources/logging/EntityEventPolicyMsgs.properties12
-rw-r--r--src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyStubbed.java34
-rw-r--r--src/test/java/org/onap/aai/datarouter/policy/SpikeEntityEventPolicyTest.java90
-rw-r--r--src/test/resources/spike_event.json23
10 files changed, 1279 insertions, 35 deletions
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<String> searchTagCollection = new ArrayList<>();
+ protected ArrayList<String> searchTagIdCollection = new ArrayList<>();
+ protected ArrayList<String> 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<String> 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<String> 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<String> searchTagCollection) {
+ this.searchTagCollection = searchTagCollection;
+ }
+
+ public void setSearchTags(String searchTags) {
+ this.searchTags = searchTags;
+ }
+
+ public ArrayList<String> getSearchTagIdCollection() {
+ return searchTagIdCollection;
+ }
+
+ public void setSearchTagIdCollection(ArrayList<String> 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<String> 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<ExternalOxmModelProcessor> 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<String> SUPPORTED_ACTIONS =
+ Arrays.asList(ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE);
+
+ Map<String, DynamicJAXBContext> 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<String> 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<DatabaseField> 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<String> 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<String> 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<String> fieldValues = null;
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+ for (Map.Entry<String, String> 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<String> primaryKeyValues = new ArrayList<>();
+ List<String> 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<String> 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<String, List<String>> 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<String> 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<String> 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"
+}