Renaming openecomp to onap
[aai/data-router.git] / src / main / java / org / openecomp / datarouter / policy / EntityEventPolicy.java
index afddad2..cee12da 100644 (file)
@@ -1,16 +1,15 @@
 /**
  * ============LICENSE_START=======================================================
- * DataRouter
+ * org.onap.aai
  * ================================================================================
- * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
  * 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
+ *       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,
  * limitations under the License.
  * ============LICENSE_END=========================================================
  *
- * ECOMP and OpenECOMP are trademarks
- * and service marks of AT&T Intellectual Property.
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  */
 package org.openecomp.datarouter.policy;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectWriter;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.sun.jersey.core.util.MultivaluedMapImpl;
-
-import java.io.BufferedReader;
+import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -43,53 +32,52 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
-import org.eclipse.jetty.util.security.Password;
 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.datarouter.entity.AaiEventEntity;
+import org.onap.aai.datarouter.entity.AggregationEntity;
+import org.onap.aai.datarouter.entity.DocumentStoreDataEntity;
+import org.onap.aai.datarouter.entity.OxmEntityDescriptor;
+import org.onap.aai.datarouter.entity.SuggestionSearchEntity;
+import org.onap.aai.datarouter.entity.TopographicalEntity;
+import org.onap.aai.datarouter.entity.UebEventHeader;
 import org.openecomp.cl.api.Logger;
 import org.openecomp.cl.eelf.LoggerFactory;
 import org.openecomp.cl.mdc.MdcContext;
-import org.openecomp.datarouter.entity.AaiEventEntity;
-import org.openecomp.datarouter.entity.AggregationEntity;
-import org.openecomp.datarouter.entity.DocumentStoreDataEntity;
-import org.openecomp.datarouter.entity.OxmEntityDescriptor;
-import org.openecomp.datarouter.entity.SuggestionSearchEntity;
-import org.openecomp.datarouter.entity.TopographicalEntity;
-import org.openecomp.datarouter.entity.UebEventHeader;
 import org.openecomp.datarouter.logging.EntityEventPolicyMsgs;
 import org.openecomp.datarouter.util.CrossEntityReference;
-import org.openecomp.datarouter.util.DataRouterConstants;
 import org.openecomp.datarouter.util.EntityOxmReferenceHelper;
 import org.openecomp.datarouter.util.ExternalOxmModelProcessor;
+import org.openecomp.datarouter.util.NodeUtils;
 import org.openecomp.datarouter.util.OxmModelLoader;
 import org.openecomp.datarouter.util.RouterServiceUtil;
+import org.openecomp.datarouter.util.SearchServiceAgent;
 import org.openecomp.datarouter.util.SearchSuggestionPermutation;
 import org.openecomp.datarouter.util.Version;
 import org.openecomp.datarouter.util.VersionedOxmEntities;
-import org.openecomp.restclient.client.Headers;
-import org.openecomp.restclient.client.OperationResult;
-import org.openecomp.restclient.client.RestClient;
-import org.openecomp.restclient.rest.HttpUtil;
-import org.openecomp.datarouter.util.NodeUtils;
+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;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
 public class EntityEventPolicy implements Processor {
 
   public static final String additionalInfo = "Response of AAIEntityEventPolicy";
   private static final String entitySearchSchema = "entitysearch_schema.json";
   private static final String topographicalSearchSchema   = "topographysearch_schema.json";
   private Collection<ExternalOxmModelProcessor> externalOxmModelProcessors;
-  RestClient searchClient = null;
 
   private final String EVENT_HEADER = "event-header";
   private final String ENTITY_HEADER = "entity";
@@ -106,12 +94,19 @@ public class EntityEventPolicy implements Processor {
   Map<String, DynamicJAXBContext> oxmVersionContextMap = new HashMap<>();
   private String oxmVersion = null;
 
-  private String entityIndexTarget = null;
-  private String entitySearchTarget = null;
-  private String topographicalIndexTarget = null;
-  private String topographicalSearchTarget = null;
-  private String autoSuggestSearchTarget = null;
-  private String aggregationSearchVnfTarget = null;
+  /** Agent for communicating with the Search Service. */
+  private SearchServiceAgent searchAgent = null;
+  
+  /** Search index name for storing AAI event entities. */
+  private String entitySearchIndex;
+
+  /** Search index name for storing topographical search data. */
+  private String topographicalSearchIndex;
+  
+  /** Search index name for suggestive search data. */
+  private String aggregateGenericVnfIndex;
+  
+  private String autosuggestIndex;
 
   private String srcDomain;
 
@@ -123,7 +118,7 @@ public class EntityEventPolicy implements Processor {
     SUCCESS, PARTIAL_SUCCESS, FAILURE;
   };
 
-  public EntityEventPolicy(EntityEventPolicyConfig config) {
+  public EntityEventPolicy(EntityEventPolicyConfig config) throws FileNotFoundException {
     LoggerFactory loggerFactoryInstance = LoggerFactory.getInstance();
     logger = loggerFactoryInstance.getLogger(EntityEventPolicy.class.getName());
     metricsLogger = loggerFactoryInstance.getMetricsLogger(EntityEventPolicy.class.getName());
@@ -131,34 +126,19 @@ public class EntityEventPolicy implements Processor {
 
     srcDomain = config.getSourceDomain();
 
-    entityIndexTarget =
-      EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint(),
-        config.getSearchEntitySearchIndex());
-
-    entitySearchTarget =
-        EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint(),
-            config.getSearchEntitySearchIndex(), config.getSearchEndpointDocuments());
-
-    topographicalIndexTarget =
-      EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint(),
-        config.getSearchTopographySearchIndex());
-
-    topographicalSearchTarget = EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(),
-        config.getSearchEndpoint(), config.getSearchTopographySearchIndex());
-
-    // Create REST client for search service
-    searchClient = new RestClient().validateServerHostname(false).validateServerCertChain(true)
-        .clientCertFile(DataRouterConstants.DR_HOME_AUTH + config.getSearchCertName())
-        .clientCertPassword(Password.deobfuscate(config.getSearchKeystorePwd()))
-        .trustStore(DataRouterConstants.DR_HOME_AUTH + config.getSearchKeystore());
-
-    autoSuggestSearchTarget =
-        EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint(),
-            config.getSearchEntityAutoSuggestIndex(), config.getSearchEndpointDocuments());
-
-    aggregationSearchVnfTarget =
-        EntityEventPolicy.concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint(),
-            config.getSearchAggregationVnfIndex(), config.getSearchEndpointDocuments());
+    // Populate the index names.
+    entitySearchIndex        = config.getSearchEntitySearchIndex();
+    topographicalSearchIndex = config.getSearchTopographySearchIndex();
+    aggregateGenericVnfIndex = config.getSearchAggregationVnfIndex();
+       
+    // 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<ExternalOxmModelProcessor>();
     this.externalOxmModelProcessors.add(EntityOxmReferenceHelper.getInstance());
@@ -193,73 +173,12 @@ public class EntityEventPolicy implements Processor {
   public void startup() {
     
     // Create the indexes in the search service if they do not already exist.
-    createSearchIndex(entityIndexTarget, entitySearchSchema);
-    createSearchIndex(topographicalIndexTarget, topographicalSearchSchema);
+    searchAgent.createSearchIndex(entitySearchIndex, entitySearchSchema);
+    searchAgent.createSearchIndex(topographicalSearchIndex, topographicalSearchSchema);
     
     logger.info(EntityEventPolicyMsgs.ENTITY_EVENT_POLICY_REGISTERED);
   }
 
-  /**
-   * Creates an index through the search db abstraction
-   * 
-   * @param searchRESTClient
-   *            the REST client configured to contact the search db
-   *            abstraction
-   * @param searchTarget
-   *            the URL to attempt to create the search index
-   * @param schemaLocation
-   *            the location of the mappings file for the index
-   */
-  private void createSearchIndex(String searchTarget, String schemaLocation) {
-     
-    logger.debug("Creating search index, searchTarget = " + searchTarget + ", schemaLocation = " + schemaLocation);
-           
-    MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
-    headers.put("Accept", Arrays.asList("application/json"));
-    headers.put(Headers.FROM_APP_ID, Arrays.asList("DL"));
-    headers.put(Headers.TRANSACTION_ID, Arrays.asList(UUID.randomUUID().toString()));
-      
-    try {
-
-      OperationResult result = searchClient.put(searchTarget, loadFileData(schemaLocation), headers,
-                                                MediaType.APPLICATION_JSON_TYPE, null);
-
-      if (!HttpUtil.isHttpResponseClassSuccess(result.getResultCode())) {
-        logger.error(EntityEventPolicyMsgs.FAIL_TO_CREATE_SEARCH_INDEX, searchTarget, result.getFailureCause());
-      } else {
-        logger.info(EntityEventPolicyMsgs.SEARCH_INDEX_CREATE_SUCCESS, searchTarget);
-      }
-
-    } catch (Exception e) {
-      logger.error(EntityEventPolicyMsgs.FAIL_TO_CREATE_SEARCH_INDEX, searchTarget, e.getLocalizedMessage());
-    }
-  }
-
-  /**
-   * Convenience method to load up all the data from a file into a string
-   * 
-   * @param filename the filename to read from disk
-   * @return the data contained within the file
-   * @throws Exception
-   */
-  protected String loadFileData(String filename) throws Exception {
-    StringBuilder data = new StringBuilder();
-    try {
-      BufferedReader in = new BufferedReader(new InputStreamReader(
-          EntityEventPolicy.class.getClassLoader().getResourceAsStream("/" + filename),
-          StandardCharsets.UTF_8));
-      String line;
-
-      while ((line = in.readLine()) != null) {
-        data.append(line);
-      }
-    } catch (Exception e) {
-      throw new Exception("Failed to read from file = " + filename + ".", e);
-    }
-
-    return data.toString();
-  }
-
 
   /**
    * Convert object to json.
@@ -306,9 +225,15 @@ public class EntityEventPolicy implements Processor {
     }
 
     // Load the UEB payload data, any errors will result in a failure and discard
-    JSONObject uebObjHeader = getUebHeaderAsJson(uebPayload);
+    JSONObject uebObjHeader = getUebContentAsJson(uebPayload, EVENT_HEADER);
     if (uebObjHeader == null) {
-      returnWithError(exchange, uebPayload, "Payload is missing event-header");
+      returnWithError(exchange, uebPayload, "Payload is missing " + EVENT_HEADER);
+      return;
+    }
+    
+    JSONObject uebObjEntity = getUebContentAsJson(uebPayload, ENTITY_HEADER);
+    if (uebObjEntity == null) {
+      returnWithError(exchange, uebPayload, "Payload is missing " + ENTITY_HEADER);
       return;
     }
 
@@ -456,7 +381,7 @@ public class EntityEventPolicy implements Processor {
       return;
     }
 
-    handleSearchServiceOperation(aaiEventEntity, action, this.entitySearchTarget);
+    handleSearchServiceOperation(aaiEventEntity, action, entitySearchIndex);
 
     handleTopographicalData(uebPayload, action, entityType, oxmEntityType, oxmJaxbContext,
         entityPrimaryKeyFieldName, entityPrimaryKeyFieldValue);
@@ -612,9 +537,17 @@ public class EntityEventPolicy implements Processor {
       Map<String, OxmEntityDescriptor> rootDescriptor =
           oxmEntities.getSuggestableEntityDescriptors();
       if (!rootDescriptor.isEmpty()) {
-        List<String> suggestibleAttributes = extractSuggestableAttr(oxmEntities, entityType);
+        List<String> suggestibleAttrInPayload = new ArrayList<String>();
+        List<String> suggestibleAttrInOxm = extractSuggestableAttr(oxmEntities, entityType);
+        if (suggestibleAttrInOxm != null) {
+          for (String attr: suggestibleAttrInOxm){
+            if ( uebObjEntity.has(attr) ){
+              suggestibleAttrInPayload.add(attr);
+            }
+          }
+        }
 
-        if (suggestibleAttributes == null) {
+        if (suggestibleAttrInPayload.isEmpty()) {
           return;
         }
 
@@ -623,40 +556,38 @@ public class EntityEventPolicy implements Processor {
         ae.setLink(entityLink);
         ae.deriveFields(uebAsJson);
 
-        handleSuggestiveSearchData(ae, action, this.aggregationSearchVnfTarget);
+        handleSearchServiceOperation(ae, action, aggregateGenericVnfIndex);
 
         /*
          * 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)) {
-          SearchSuggestionPermutation searchSuggestionPermutation =
-              new SearchSuggestionPermutation();
-          List<ArrayList<String>> permutationsOfStatuses =
-              searchSuggestionPermutation.getSuggestionsPermutation(suggestibleAttributes);
-
-          // Now we have a list of all possible permutations for the status that are
-          // defined for this entity type. Try inserting a document for every combination.
-          for (ArrayList<String> permutation : permutationsOfStatuses) {
+          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(permutation);
-            suggestionSearchEntity.setPayloadFromResponse(uebAsJson);
+            suggestionSearchEntity.setSuggestableAttr(list);
             suggestionSearchEntity.setEntityTypeAliases(suggestionAliases);
+            suggestionSearchEntity.setFilterBasedPayloadFromResponse(uebAsJson.get("entity"),
+                suggestibleAttrInOxm, list);
             suggestionSearchEntity.setSuggestionInputPermutations(
                 suggestionSearchEntity.generateSuggestionInputPermutations());
 
             if (suggestionSearchEntity.isSuggestableDoc()) {
               try {
-                suggestionSearchEntity.deriveFields();
+                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());
               }
 
-              handleSuggestiveSearchData(suggestionSearchEntity, action,
-                  this.autoSuggestSearchTarget);
+              handleSearchServiceOperation(suggestionSearchEntity, action, autosuggestIndex);
             }
           }
         }
@@ -727,10 +658,10 @@ public class EntityEventPolicy implements Processor {
   /*
    * Load the UEB JSON payload, any errors would result to a failure case response.
    */
-  private JSONObject getUebHeaderAsJson(String payload) {
+  private JSONObject getUebContentAsJson(String payload, String contentKey) {
 
     JSONObject uebJsonObj;
-    JSONObject uebObjHeader;
+    JSONObject uebObjContent;
 
     try {
       uebJsonObj = new JSONObject(payload);
@@ -740,15 +671,15 @@ public class EntityEventPolicy implements Processor {
       return null;
     }
 
-    if (uebJsonObj.has(EVENT_HEADER)) {
-      uebObjHeader = uebJsonObj.getJSONObject(EVENT_HEADER);
+    if (uebJsonObj.has(contentKey)) {
+      uebObjContent = uebJsonObj.getJSONObject(contentKey);
     } else {
-      logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_HEADER);
-      logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_HEADER);
+      logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey);
+      logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey);
       return null;
     }
 
-    return uebObjHeader;
+    return uebObjContent;
   }
 
 
@@ -955,8 +886,7 @@ public class EntityEventPolicy implements Processor {
       String jsonPayload = aaiEventEntity.getAsJson();
 
       // Run the GET to retrieve the ETAG from the search service
-      OperationResult storedEntity =
-          searchClient.get(entitySearchTarget+entityId, headers, MediaType.APPLICATION_JSON_TYPE);
+      OperationResult storedEntity = searchAgent.getDocument(entitySearchIndex, entityId);
 
       if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
         /*
@@ -971,7 +901,7 @@ public class EntityEventPolicy implements Processor {
           headers.put(Headers.IF_MATCH, etag);
         } else {
           logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE,
-              entitySearchTarget + entityId, entityId);
+                         entitySearchIndex, entityId);
         }
         
         ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
@@ -997,16 +927,14 @@ public class EntityEventPolicy implements Processor {
             // Do the PUT with new CER
             ((ObjectNode)node).put("crossEntityReferenceValues", newCer);
             jsonPayload = NodeUtils.convertObjectToJson(node, false);
-            searchClient.put(entitySearchTarget + entityId, jsonPayload, headers,
-                MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+            searchAgent.putDocument(entitySearchIndex, entityId, jsonPayload, headers);
           }
          }
       } else {
 
         if (storedEntity.getResultCode() == 404) {
           // entity not found, so attempt to do a PUT
-          searchClient.put(entitySearchTarget + entityId, aaiEventEntity.getAsJson(), headers,
-              MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+          searchAgent.putDocument(entitySearchIndex, entityId, aaiEventEntity.getAsJson(), headers);
         } else {
           logger.error(EntityEventPolicyMsgs.FAILED_TO_UPDATE_ENTITY_IN_DOCSTORE,
               aaiEventEntity.getId(), "SYNC_ENTITY");
@@ -1027,76 +955,9 @@ public class EntityEventPolicy implements Processor {
    * @param target Resource to perform the operation on
    * @param allowDeleteEvent Allow delete operation to be performed on resource
    */
-  private void handleSuggestiveSearchData(DocumentStoreDataEntity eventEntity, String action,
-      String target) {
-    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 =
-            searchClient.get(target + entityId, headers, MediaType.APPLICATION_JSON_TYPE);
-
-        if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
-          List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
-
-          if (etag != null && etag.size() > 0) {
-            headers.put(Headers.IF_MATCH, etag);
-          } else {
-            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
-                entityId);
-          }
-        }
-
-        String eventEntityStr = eventEntity.getAsJson();
-
-        if (eventEntityStr != null) {
-          searchClient.put(target + entityId, eventEntity.getAsJson(), headers,
-              MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
-        }
-      } else if (action.equalsIgnoreCase(ACTION_CREATE)) {
-        String eventEntityStr = eventEntity.getAsJson();
-
-        if (eventEntityStr != null) {
-          searchClient.post(target, eventEntityStr, headers, MediaType.APPLICATION_JSON_TYPE,
-              MediaType.APPLICATION_JSON_TYPE);
-        }
-      } else if (action.equalsIgnoreCase(ACTION_DELETE)) {
-        // Run the GET to retrieve the ETAG from the search service
-        OperationResult storedEntity =
-            searchClient.get(target + entityId, headers, MediaType.APPLICATION_JSON_TYPE);
-
-        if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
-          List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
-
-          if (etag != null && etag.size() > 0) {
-            headers.put(Headers.IF_MATCH, etag);
-          } else {
-            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
-                entityId);
-          }
-
-          searchClient.delete(target + eventEntity.getId(), headers, null);
-        } else {
-          logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
-              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);
-    }
-  }
-
-  private void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action,
-      String target) {
+  protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, 
+                                            String                  action,
+                                            String                  index) {
     try {
 
       Map<String, List<String>> headers = new HashMap<>();
@@ -1111,8 +972,7 @@ public class EntityEventPolicy implements Processor {
           || action.equalsIgnoreCase(ACTION_UPDATE)) {
 
         // Run the GET to retrieve the ETAG from the search service
-        OperationResult storedEntity =
-            searchClient.get(target + entityId, headers, MediaType.APPLICATION_JSON_TYPE);
+        OperationResult storedEntity = searchAgent.getDocument(index, entityId);
 
         if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
           List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
@@ -1120,20 +980,21 @@ public class EntityEventPolicy implements Processor {
           if (etag != null && etag.size() > 0) {
             headers.put(Headers.IF_MATCH, etag);
           } else {
-            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
+            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index,
                 entityId);
           }
         }
 
-        searchClient.put(target + entityId, eventEntity.getAsJson(), headers,
-            MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+        // Write the entity to the search service.
+        // PUT
+        searchAgent.putDocument(index, entityId, eventEntity.getAsJson(), headers);
       } else if (action.equalsIgnoreCase(ACTION_CREATE)) {
-        searchClient.post(target, eventEntity.getAsJson(), headers, MediaType.APPLICATION_JSON_TYPE,
-            MediaType.APPLICATION_JSON_TYPE);
+        // 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 =
-            searchClient.get(target + entityId, headers, MediaType.APPLICATION_JSON_TYPE);
+        OperationResult storedEntity = searchAgent.getDocument(index, entityId);
 
         if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
           List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
@@ -1141,13 +1002,13 @@ public class EntityEventPolicy implements Processor {
           if (etag != null && etag.size() > 0) {
             headers.put(Headers.IF_MATCH, etag);
           } else {
-            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
+            logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index,
                 entityId);
           }
 
-          searchClient.delete(target + eventEntity.getId(), headers, null);
+          searchAgent.deleteDocument(index, eventEntity.getId(), headers);
         } else {
-          logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, target + entityId,
+          logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index,
               entityId);
         }
       } else {
@@ -1202,7 +1063,7 @@ public class EntityEventPolicy implements Processor {
           "Cannot create unique SHA digest for topographical data.");
     }
 
-    this.handleSearchServiceOperation(topoEntity, action, this.topographicalSearchTarget);
+    this.handleSearchServiceOperation(topoEntity, action, topographicalSearchIndex);
   }