Process VNF event from spike 37/37137/2
authorrv871f <richard.vondadelszen@amdocs.com>
Tue, 20 Mar 2018 14:21:42 +0000 (10:21 -0400)
committerrv871f <richard.vondadelszen@amdocs.com>
Tue, 20 Mar 2018 15:03:34 +0000 (11:03 -0400)
Issue-ID: AAI-899
Change-Id: I2d056734e6af0fe0b4efe92681971e2b74153a0e
Signed-off-by: rv871f <richard.vondadelszen@amdocs.com>
17 files changed:
src/main/java/org/onap/aai/datarouter/entity/SpikeAggregationEntity.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/policy/AbstractSpikeEntityEventProcessor.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/policy/EntityEventPolicy.java
src/main/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessor.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/policy/SpikeAutosuggestIndexProcessor.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessor.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfig.java [new file with mode: 0644]
src/main/java/org/onap/aai/datarouter/util/SearchServiceAgent.java
src/main/resources/aggregatevnf_schema.json [new file with mode: 0644]
src/main/resources/autosuggest_schema.json [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorStubbed.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeAggregateGenericVnfProcessorTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorStubbed.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeAutosuggestProcessorTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorStubbed.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeEntitySearchProcessorTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/datarouter/policy/SpikeEventPolicyConfigTest.java [new file with mode: 0644]

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