2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 package org.onap.aai.datarouter.policy;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.security.NoSuchAlgorithmException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
34 import org.apache.camel.Exchange;
35 import org.apache.camel.Processor;
36 import org.eclipse.persistence.dynamic.DynamicType;
37 import org.eclipse.persistence.internal.helper.DatabaseField;
38 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
39 import org.json.JSONException;
40 import org.json.JSONObject;
41 import org.onap.aai.cl.api.Logger;
42 import org.onap.aai.cl.eelf.LoggerFactory;
43 import org.onap.aai.cl.mdc.MdcContext;
44 import org.onap.aai.datarouter.entity.DocumentStoreDataEntity;
45 import org.onap.aai.datarouter.entity.OxmEntityDescriptor;
46 import org.onap.aai.datarouter.entity.SpikeEventEntity;
47 import org.onap.aai.datarouter.entity.SpikeEventVertex;
48 import org.onap.aai.datarouter.logging.EntityEventPolicyMsgs;
49 import org.onap.aai.datarouter.util.EntityOxmReferenceHelper;
50 import org.onap.aai.datarouter.util.ExternalOxmModelProcessor;
51 import org.onap.aai.datarouter.util.OxmModelLoader;
52 import org.onap.aai.datarouter.util.RouterServiceUtil;
53 import org.onap.aai.datarouter.util.SearchServiceAgent;
54 import org.onap.aai.restclient.client.Headers;
55 import org.onap.aai.restclient.client.OperationResult;
56 import org.onap.aai.restclient.rest.HttpUtil;
59 import com.fasterxml.jackson.core.JsonProcessingException;
60 import com.fasterxml.jackson.databind.JsonNode;
61 import com.fasterxml.jackson.databind.ObjectMapper;
62 import com.fasterxml.jackson.databind.ObjectWriter;
64 public abstract class AbstractSpikeEntityEventProcessor implements Processor {
66 protected static final String additionalInfo = "Response of SpikeEntityEventPolicy";
67 private Collection<ExternalOxmModelProcessor> externalOxmModelProcessors;
70 protected final String ACTION_CREATE = "create";
71 private final String EVENT_VERTEX = "vertex";
72 public final static String ACTION_DELETE = "delete";
73 protected final String ACTION_UPDATE = "update";
74 protected final String PROCESS_SPIKE_EVENT = "Process Spike Event";
75 private final String OPERATION_KEY = "operation";
77 protected enum ResponseType {
78 SUCCESS, PARTIAL_SUCCESS, FAILURE;
81 private final List<String> SUPPORTED_ACTIONS =
82 Arrays.asList(ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE);
84 Map<String, DynamicJAXBContext> oxmVersionContextMap = new HashMap<>();
85 private String oxmVersion = null;
87 /** Agent for communicating with the Search Service. */
88 protected SearchServiceAgent searchAgent = null;
89 protected String searchIndexName;
90 protected String searchIndexSchema;
91 protected String createIndexUrl;
93 protected Logger logger;
94 protected Logger metricsLogger;
95 protected ObjectMapper mapper;
98 public AbstractSpikeEntityEventProcessor(SpikeEventPolicyConfig config)
99 throws FileNotFoundException {
100 mapper = new ObjectMapper();
101 LoggerFactory loggerFactoryInstance = LoggerFactory.getInstance();
102 logger = loggerFactoryInstance.getLogger(AbstractSpikeEntityEventProcessor.class.getName());
104 loggerFactoryInstance.getMetricsLogger(AbstractSpikeEntityEventProcessor.class.getName());
106 // Instantiate the agent that we will use for interacting with the Search Service.
107 searchAgent = new SearchServiceAgent(config.getSearchCertName(), config.getSearchKeystore(),
108 config.getSearchKeystorePwd(), AbstractSpikeEntityEventProcessor
109 .concatSubUri(config.getSearchBaseUrl(), config.getSearchEndpoint()),
110 config.getSearchEndpointDocuments(), logger);
112 this.externalOxmModelProcessors = new ArrayList<>();
113 this.externalOxmModelProcessors.add(EntityOxmReferenceHelper.getInstance());
114 OxmModelLoader.registerExternalOxmModelProcessors(externalOxmModelProcessors);
115 OxmModelLoader.loadModels();
116 oxmVersionContextMap = OxmModelLoader.getVersionContextMap();
117 parseLatestOxmVersion();
120 public String getCreateIndexUrl() {
121 return createIndexUrl;
125 public void setCreateIndexUrl(String createIndexUrl) {
126 this.createIndexUrl = createIndexUrl;
129 public String getSearchIndexName() {
130 return searchIndexName;
134 public void setSearchIndexName(String searchIndexName) {
135 this.searchIndexName = searchIndexName;
138 public String getSearchIndexSchema() {
139 return searchIndexSchema;
143 public void setSearchIndexSchema(String searchIndexSchema) {
144 this.searchIndexSchema = searchIndexSchema;
147 protected void startup() {
152 * Load the UEB JSON payload, any errors would result to a failure case response.
154 protected JSONObject getUebContentAsJson(String payload, String contentKey) {
156 JSONObject uebJsonObj;
157 JSONObject uebObjContent;
160 uebJsonObj = new JSONObject(payload);
161 } catch (JSONException e) {
162 logger.debug(EntityEventPolicyMsgs.UEB_INVALID_PAYLOAD_JSON_FORMAT, payload);
163 logger.error(EntityEventPolicyMsgs.UEB_INVALID_PAYLOAD_JSON_FORMAT, payload);
167 if (uebJsonObj.has(contentKey)) {
168 uebObjContent = uebJsonObj.getJSONObject(contentKey);
170 logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey);
171 logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, contentKey);
175 return uebObjContent;
177 public abstract void process(Exchange exchange) throws Exception;
180 private void parseLatestOxmVersion() {
181 int latestVersion = -1;
182 if (oxmVersionContextMap != null) {
183 Iterator it = oxmVersionContextMap.entrySet().iterator();
184 while (it.hasNext()) {
185 Map.Entry pair = (Map.Entry) it.next();
187 String version = pair.getKey().toString();
188 int versionNum = Integer.parseInt(version.substring(1, version.length()));
190 if (versionNum > latestVersion) {
191 latestVersion = versionNum;
192 oxmVersion = pair.getKey().toString();
195 logger.info(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_FOUND, pair.getKey().toString());
198 logger.error(EntityEventPolicyMsgs.PROCESS_OXM_MODEL_MISSING, "");
205 * This will be used in: updateSearchEntityWithCrossEntityReference not this scope Convert object
208 * @param object the object
209 * @param pretty the pretty
211 * @throws JsonProcessingException the json processing exception
213 * protected static String convertObjectToJson(Object object, boolean pretty) throws
214 * JsonProcessingException { ObjectWriter ow;
216 * if (pretty) { ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
218 * } else { ow = new ObjectMapper().writer(); }
220 * return ow.writeValueAsString(object); }
223 protected void returnWithError(Exchange exchange, String payload, String errorMsg) {
224 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE, errorMsg);
225 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, errorMsg, payload);
226 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
229 private boolean isJSONValid(String test) {
231 new JSONObject(test);
232 } catch (JSONException ex) {
240 protected String getSpikeEventAction(Exchange exchange, String uebPayload) {
241 JSONObject mainJson = new JSONObject(uebPayload);
242 String action = mainJson.getString(OPERATION_KEY);
243 if (action == null || !SUPPORTED_ACTIONS.contains(action.toLowerCase())) {
244 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
245 "Unrecognized action '" + action + "'", uebPayload);
246 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
247 "Unrecognized action '" + action + "'");
248 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
254 protected String getExchangeBody(Exchange exchange) {
255 String uebPayload = exchange.getIn().getBody().toString();
256 if (uebPayload == null || !isJSONValid(uebPayload)) {
257 uebPayload = exchange.getIn().getBody(String.class);
258 if (uebPayload == null || !isJSONValid(uebPayload)) {
259 returnWithError(exchange, uebPayload, "Invalid Payload");
266 protected SpikeEventVertex populateEventVertex(Exchange exchange, String uebPayload)
269 // Load the UEB payload data, any errors will result in a failure and discard
271 JSONObject spikeObjVertex = getUebContentAsJson(uebPayload, EVENT_VERTEX);
272 if (spikeObjVertex == null) {
273 returnWithError(exchange, uebPayload, "Payload is missing " + EVENT_VERTEX);
277 SpikeEventVertex eventVertex = initializeSpikeEventVertex(spikeObjVertex.toString());
281 protected DynamicJAXBContext readOxm(Exchange exchange, String uebPayload) {
282 DynamicJAXBContext oxmJaxbContext = loadOxmContext(oxmVersion.toLowerCase());
283 if (oxmJaxbContext == null) {
284 logger.error(EntityEventPolicyMsgs.OXM_VERSION_NOT_SUPPORTED, oxmVersion);
285 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "OXM version mismatch", uebPayload);
287 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
290 return oxmJaxbContext;
294 protected String getEntityType(Exchange exchange, SpikeEventVertex eventVertex,
297 String entityType = eventVertex.getType();
298 if (entityType == null || entityType.isEmpty()) {
299 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
300 "Payload header missing entity type", uebPayload);
301 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
302 "Payload header missing entity type");
304 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
312 protected String getEntityLink(Exchange exchange, SpikeEventVertex eventVertex,
314 String entityKey = eventVertex.getKey();
315 if (entityKey == null || entityKey.isEmpty()) {
316 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Payload vertex missing entity key",
318 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
319 "Payload vertex missing entity key");
321 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
324 //EntityLink never can be null if entityKey is not null. no need to check
325 return eventVertex.getEntityLink();
332 * Use the OXM Model to determine the primary key field name based on the entity-type
334 protected SpikeEventEntity populateSpikeEventEntity(Exchange exchange,
335 SpikeEventEntity spikeEventEntity, DynamicJAXBContext oxmJaxbContext, String entityType,
336 String action, String uebPayload, String oxmEntityType, List<String> searchableAttr) {
338 String entityPrimaryKeyFieldName =
339 getEntityPrimaryKeyFieldName(oxmJaxbContext, uebPayload, oxmEntityType, entityType);
340 if (entityPrimaryKeyFieldName == null) {
341 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
342 "Payload missing primary key attribute");
343 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
344 "Payload missing primary key attribute", uebPayload);
345 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
348 String entityPrimaryKeyFieldValue = lookupValueUsingKey(uebPayload, entityPrimaryKeyFieldName);
349 if (entityPrimaryKeyFieldValue.isEmpty()) {
350 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
351 "Payload missing primary value attribute");
352 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
353 "Payload missing primary value attribute", uebPayload);
355 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
360 if (!getSearchTags(spikeEventEntity, searchableAttr, uebPayload, action)) {
361 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
362 "Payload missing searchable attribute for entity type '" + entityType + "'");
363 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
364 "Payload missing searchable attribute for entity type '" + entityType + "'", uebPayload);
366 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
369 spikeEventEntity.setEntityPrimaryKeyName(entityPrimaryKeyFieldName);
370 spikeEventEntity.setEntityPrimaryKeyValue(entityPrimaryKeyFieldName);
373 spikeEventEntity.deriveFields();
375 } catch (NoSuchAlgorithmException e) {
376 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest");
377 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE, "Cannot create unique SHA digest",
380 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
383 return spikeEventEntity;
386 protected void setResponse(Exchange exchange, ResponseType responseType, String additionalInfo) {
388 exchange.getOut().setHeader("ResponseType", responseType.toString());
389 exchange.getOut().setBody(additionalInfo);
393 protected String getOxmEntityType(String entityType) {
395 String[] entityTypeArr = entityType.split("-");
396 String oxmEntityType = "";
397 for (String entityWord : entityTypeArr) {
398 oxmEntityType += entityWord.substring(0, 1).toUpperCase() + entityWord.substring(1);
400 return oxmEntityType;
403 protected List<String> getSearchableAttibutes(DynamicJAXBContext oxmJaxbContext, String oxmEntityType,
404 String entityType, String uebPayload,Exchange exchange) {
405 List<String> searchableAttr =
406 getOxmAttributes(oxmJaxbContext, oxmEntityType, entityType, "searchable");
407 if (searchableAttr == null) {
408 logger.error(EntityEventPolicyMsgs.DISCARD_EVENT_NONVERBOSE,
409 "Searchable attribute not found for payload entity type '" + entityType + "'");
410 logger.debug(EntityEventPolicyMsgs.DISCARD_EVENT_VERBOSE,
411 "Searchable attribute not found for payload entity type '" + entityType + "'",
414 setResponse(exchange, ResponseType.FAILURE, additionalInfo);
417 return searchableAttr;
421 private SpikeEventVertex initializeSpikeEventVertex(String payload) {
423 SpikeEventVertex eventVertex = null;
424 ObjectMapper mapper = new ObjectMapper();
426 // Make sure that were were actually passed in a valid string.
427 if (payload == null || payload.isEmpty()) {
428 logger.debug(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_VERTEX);
429 logger.error(EntityEventPolicyMsgs.UEB_FAILED_TO_PARSE_PAYLOAD, EVENT_VERTEX);
434 // Marshal the supplied string into a UebEventHeader object.
436 eventVertex = mapper.readValue(payload, SpikeEventVertex.class);
437 } catch (JsonProcessingException e) {
438 logger.error(EntityEventPolicyMsgs.UEB_FAILED_UEBEVENTHEADER_CONVERSION, e.toString());
439 } catch (Exception e) {
440 logger.error(EntityEventPolicyMsgs.UEB_FAILED_UEBEVENTHEADER_CONVERSION, e.toString());
443 if (eventVertex != null) {
444 logger.debug(EntityEventPolicyMsgs.UEB_EVENT_HEADER_PARSED, eventVertex.toString());
451 private String getEntityPrimaryKeyFieldName(DynamicJAXBContext oxmJaxbContext, String payload,
452 String oxmEntityType, String entityType) {
454 DynamicType entity = oxmJaxbContext.getDynamicType(oxmEntityType);
455 if (entity == null) {
459 List<DatabaseField> list = entity.getDescriptor().getPrimaryKeyFields();
460 if (list != null && !list.isEmpty()) {
461 String keyName = list.get(0).getName();
462 return keyName.substring(0, keyName.indexOf('/'));
468 private String lookupValueUsingKey(String payload, String key) throws JSONException {
469 JsonNode jsonNode = convertToJsonNode(payload);
470 return RouterServiceUtil.recursivelyLookupJsonPayload(jsonNode, key);
474 private JsonNode convertToJsonNode(String payload) {
476 ObjectMapper mapper = new ObjectMapper();
477 JsonNode jsonNode = null;
479 jsonNode = mapper.readTree(mapper.getJsonFactory().createJsonParser(payload));
480 } catch (IOException e) {
481 logger.debug(EntityEventPolicyMsgs.FAILED_TO_PARSE_UEB_PAYLOAD, EVENT_VERTEX + " missing",
483 logger.error(EntityEventPolicyMsgs.FAILED_TO_PARSE_UEB_PAYLOAD, EVENT_VERTEX + " missing",
491 private boolean getSearchTags(SpikeEventEntity spikeEventEntity, List<String> searchableAttr,
492 String payload, String action) {
494 boolean hasSearchableAttr = false;
495 for (String searchTagField : searchableAttr) {
496 String searchTagValue;
497 if (searchTagField.equalsIgnoreCase(spikeEventEntity.getEntityPrimaryKeyName())) {
498 searchTagValue = spikeEventEntity.getEntityPrimaryKeyValue();
500 searchTagValue = this.lookupValueUsingKey(payload, searchTagField);
503 if (searchTagValue != null && !searchTagValue.isEmpty()) {
504 hasSearchableAttr = true;
505 spikeEventEntity.addSearchTagWithKey(searchTagValue, searchTagField);
508 return hasSearchableAttr;
512 * Check if OXM version is available. If available, load it.
514 private DynamicJAXBContext loadOxmContext(String version) {
515 if (version == null) {
516 logger.error(EntityEventPolicyMsgs.FAILED_TO_FIND_OXM_VERSION, version);
520 return oxmVersionContextMap.get(version);
523 private List<String> getOxmAttributes(DynamicJAXBContext oxmJaxbContext, String oxmEntityType,
524 String entityType, String fieldName) {
526 DynamicType entity = (DynamicType) oxmJaxbContext.getDynamicType(oxmEntityType);
527 if (entity == null) {
532 * Check for searchable XML tag
534 List<String> fieldValues = null;
535 Map<String, String> properties = entity.getDescriptor().getProperties();
536 for (Map.Entry<String, String> entry : properties.entrySet()) {
537 if (entry.getKey().equalsIgnoreCase(fieldName)) {
538 fieldValues = Arrays.asList(entry.getValue().split(","));
546 protected SpikeEventEntity getPopulatedEntity(JsonNode entityNode,
547 OxmEntityDescriptor resultDescriptor) {
548 SpikeEventEntity d = new SpikeEventEntity();
550 d.setEntityType(resultDescriptor.getEntityName());
552 List<String> primaryKeyValues = new ArrayList<>();
553 List<String> primaryKeyNames = new ArrayList<>();
556 for (String keyName : resultDescriptor.getPrimaryKeyAttributeName()) {
557 pkeyValue = RouterServiceUtil.getNodeFieldAsText(entityNode, keyName);
558 if (pkeyValue != null) {
559 primaryKeyValues.add(pkeyValue);
560 primaryKeyNames.add(keyName);
562 // logger.warn("getPopulatedDocument(), pKeyValue is null for entityType = " +
563 // resultDescriptor.getEntityName());
564 logger.error(EntityEventPolicyMsgs.PRIMARY_KEY_NULL_FOR_ENTITY_TYPE,
565 resultDescriptor.getEntityName());
569 final String primaryCompositeKeyValue = RouterServiceUtil.concatArray(primaryKeyValues, "/");
570 d.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
571 final String primaryCompositeKeyName = RouterServiceUtil.concatArray(primaryKeyNames, "/");
572 d.setEntityPrimaryKeyName(primaryCompositeKeyName);
574 final List<String> searchTagFields = resultDescriptor.getSearchableAttributes();
577 * Based on configuration, use the configured field names for this entity-Type to build a
578 * multi-value collection of search tags for elastic search entity search criteria.
582 for (String searchTagField : searchTagFields) {
583 String searchTagValue = RouterServiceUtil.getNodeFieldAsText(entityNode, searchTagField);
584 if (searchTagValue != null && !searchTagValue.isEmpty()) {
585 d.addSearchTagWithKey(searchTagValue, searchTagField);
594 // put this here until we find a better spot
596 * Helper utility to concatenate substrings of a URI together to form a proper URI.
598 * @param suburis the list of substrings to concatenate together
599 * @return the concatenated list of substrings
601 private static String concatSubUri(String... suburis) {
602 String finalUri = "";
604 for (String suburi : suburis) {
606 if (suburi != null) {
607 // Remove any leading / since we only want to append /
608 suburi = suburi.replaceFirst("^/*", "");
610 // Add a trailing / if one isn't already there
611 finalUri += suburi.endsWith("/") ? suburi : suburi + "/";
621 * Perform create, read, update or delete (CRUD) operation on search engine's suggestive search
624 * @param eventEntity Entity/data to use in operation
625 * @param action The operation to perform
627 protected void handleSearchServiceOperation(DocumentStoreDataEntity eventEntity, String action,
631 Map<String, List<String>> headers = new HashMap<>();
632 headers.put(Headers.FROM_APP_ID, Arrays.asList("DataLayer"));
633 headers.put(Headers.TRANSACTION_ID, Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID)));
635 String entityId = eventEntity.getId();
637 if ((action.equalsIgnoreCase(ACTION_CREATE) && entityId != null)
638 || action.equalsIgnoreCase(ACTION_UPDATE)) {
640 // Run the GET to retrieve the ETAG from the search service
641 OperationResult storedEntity = searchAgent.getDocument(index, entityId);
643 if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
644 List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
646 if (etag != null && !etag.isEmpty()) {
647 headers.put(Headers.IF_MATCH, etag);
649 logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId);
653 // Write the entity to the search service.
655 searchAgent.putDocument(index, entityId, eventEntity.getAsJson(), headers);
656 } else if (action.equalsIgnoreCase(ACTION_CREATE)) {
657 // Write the entry to the search service.
658 searchAgent.postDocument(index, eventEntity.getAsJson(), headers);
660 } else if (action.equalsIgnoreCase(ACTION_DELETE)) {
661 // Run the GET to retrieve the ETAG from the search service
662 OperationResult storedEntity = searchAgent.getDocument(index, entityId);
664 if (HttpUtil.isHttpResponseClassSuccess(storedEntity.getResultCode())) {
665 List<String> etag = storedEntity.getHeaders().get(Headers.ETAG);
667 if (etag != null && !etag.isEmpty()) {
668 headers.put(Headers.IF_MATCH, etag);
670 logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId);
673 searchAgent.deleteDocument(index, eventEntity.getId(), headers);
675 logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE, index, entityId);
678 logger.error(EntityEventPolicyMsgs.ENTITY_OPERATION_NOT_SUPPORTED, action);
680 } catch (IOException e) {
681 logger.error(EntityEventPolicyMsgs.FAILED_TO_UPDATE_ENTITY_IN_DOCSTORE, eventEntity.getId(),