aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openecomp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openecomp')
-rw-r--r--src/main/java/org/openecomp/datarouter/entity/AaiEventEntity.java10
-rw-r--r--src/main/java/org/openecomp/datarouter/policy/EntityEventPolicy.java96
-rw-r--r--src/main/java/org/openecomp/datarouter/util/NodeUtils.java133
3 files changed, 225 insertions, 14 deletions
diff --git a/src/main/java/org/openecomp/datarouter/entity/AaiEventEntity.java b/src/main/java/org/openecomp/datarouter/entity/AaiEventEntity.java
index 12400ad..5f44fe1 100644
--- a/src/main/java/org/openecomp/datarouter/entity/AaiEventEntity.java
+++ b/src/main/java/org/openecomp/datarouter/entity/AaiEventEntity.java
@@ -138,7 +138,7 @@ public class AaiEventEntity implements DocumentStoreDataEntity, Serializable {
}
public void deriveFields() throws NoSuchAlgorithmException {
- this.id = NodeUtils.generateUniqueShaDigest(this.getLink());
+ this.id = NodeUtils.generateUniqueShaDigest(link);
this.searchTags = concatArray(searchTagCollection, ';');
this.searchTagIds = concatArray(searchTagIdCollection, ';');
this.crossReferenceEntityValues = concatArray(crossEntityReferenceCollection, ';');
@@ -274,6 +274,14 @@ public class AaiEventEntity implements DocumentStoreDataEntity, Serializable {
* }
*/
+ public String getCrossReferenceEntityValues() {
+ return crossReferenceEntityValues;
+ }
+
+ public void setCrossReferenceEntityValues(String crossReferenceEntityValues) {
+ this.crossReferenceEntityValues = crossReferenceEntityValues;
+ }
+
@Override
public String toString() {
return "AAIEventEntity [" + (entityType != null ? "entityType=" + entityType + ", " : "")
diff --git a/src/main/java/org/openecomp/datarouter/policy/EntityEventPolicy.java b/src/main/java/org/openecomp/datarouter/policy/EntityEventPolicy.java
index 170c646..afddad2 100644
--- a/src/main/java/org/openecomp/datarouter/policy/EntityEventPolicy.java
+++ b/src/main/java/org/openecomp/datarouter/policy/EntityEventPolicy.java
@@ -28,6 +28,7 @@ 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;
@@ -65,7 +66,6 @@ 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.DataRouterMsgs;
import org.openecomp.datarouter.logging.EntityEventPolicyMsgs;
import org.openecomp.datarouter.util.CrossEntityReference;
import org.openecomp.datarouter.util.DataRouterConstants;
@@ -80,6 +80,7 @@ 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.slf4j.MDC;
public class EntityEventPolicy implements Processor {
@@ -175,7 +176,7 @@ public class EntityEventPolicy implements Processor {
Map.Entry pair = (Map.Entry) it.next();
String version = pair.getKey().toString();
- int versionNum = Integer.parseInt(version.substring(1, 2));
+ int versionNum = Integer.parseInt(version.substring(1, version.length()));
if (versionNum > latestVersion) {
latestVersion = versionNum;
@@ -467,11 +468,18 @@ public class EntityEventPolicy implements Processor {
EntityOxmReferenceHelper.getInstance().getVersionedOxmEntities(Version.valueOf(oxmVersion));
/**
- * If the entity type is "customer", the below check will return true if any nested entityType
+ * NOTES:
+ * 1. If the entity type is "customer", the below check will return true if any nested entityType
* in that model could contain a CER based on the OXM model version that has been loaded.
+ * 2. For a DELETE operation on outer/parent entity (handled by the regular flow:
+ * handleSearchServiceOperation()), ignore processing for cross-entity-reference under the
+ * assumption that AAI will push down all required cascade-deletes for nested entities as well
+ * 3. Handling the case where UEB events arrive out of order: CREATE customer is received before
+ * CREATE service-instance.
*/
- if (oxmEntities != null && oxmEntities.entityModelContainsCrossEntityReference(topEntityType)) {
+ if (!action.equalsIgnoreCase(ACTION_DELETE) && oxmEntities != null
+ && oxmEntities.entityModelContainsCrossEntityReference(topEntityType)) {
// We know the model "can" contain a CER reference definition, let's process a bit more
@@ -481,6 +489,10 @@ public class EntityEventPolicy implements Processor {
JSONObject entityJsonObject = getUebEntity(uebPayload);
JsonNode entityJsonNode = convertToJsonNode(entityJsonObject.toString());
+
+ String parentEntityType = entityType;
+
+ String targetEntityUrl = entityLink;
for (String key : crossEntityRefMap.keySet()) {
@@ -498,6 +510,19 @@ public class EntityEventPolicy implements Processor {
if (foundNodes.size() > 0) {
for (JsonNode n : foundNodes) {
+ if (parentEntityType.equalsIgnoreCase("customer")){
+ /*
+ * NOTES:
+ * 1. prepare to hand-create url for service-instance
+ * 2. this will break if the URL structure for service-instance changes
+ */
+ if (n.has("service-type")){
+ targetEntityUrl += "/service-subscriptions/service-subscription/"
+ + RouterServiceUtil.getNodeFieldAsText(n, "service-type")
+ + "/service-instances/service-instance/";
+ }
+
+ }
List<String> extractedParentEntityAttributeValues = new ArrayList<String>();
@@ -518,6 +543,16 @@ public class EntityEventPolicy implements Processor {
* 5. Put data into ES with ETAG + updated doc
*/
+ // Get the complete URL for target entity
+ if (targetEntityInstance.has("link")) { // nested SI has url mentioned
+ targetEntityUrl = RouterServiceUtil.getNodeFieldAsText(targetEntityInstance,
+ "link");
+ } else if (parentEntityType.equalsIgnoreCase("customer") &&
+ targetEntityInstance.has("service-instance-id")){
+ targetEntityUrl += "/" + RouterServiceUtil.getNodeFieldAsText(targetEntityInstance,
+ "service-instance-id");
+ }
+
OxmEntityDescriptor searchableDescriptor =
oxmEntities.getSearchableEntityDescriptor(cerDescriptor.getTargetEntityType());
@@ -540,11 +575,10 @@ public class EntityEventPolicy implements Processor {
.addCrossEntityReferenceValue(parentCrossEntityReferenceAttributeValue);
}
- entityToSync.setEntityPrimaryKeyName(entityPrimaryKeyFieldName);
- entityToSync.setLink(entityLink);
+ entityToSync.setLink(targetEntityUrl);
entityToSync.deriveFields();
- syncEntity(entityToSync);
+ updateCerInEntity(entityToSync);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
@@ -872,12 +906,14 @@ public class EntityEventPolicy implements Processor {
d.setEntityType(resultDescriptor.getEntityName());
List<String> primaryKeyValues = new ArrayList<String>();
+ List<String> primaryKeyNames = new ArrayList<String>();
String pkeyValue = null;
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());
@@ -888,6 +924,8 @@ public class EntityEventPolicy implements Processor {
final String primaryCompositeKeyValue = RouterServiceUtil.concatArray(primaryKeyValues, "/");
d.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+ final String primaryCompositeKeyName = RouterServiceUtil.concatArray(primaryKeyNames, "/");
+ d.setEntityPrimaryKeyName(primaryCompositeKeyName);
final List<String> searchTagFields = resultDescriptor.getSearchableAttributes();
@@ -907,19 +945,26 @@ public class EntityEventPolicy implements Processor {
return d;
}
- private void syncEntity(AaiEventEntity aaiEventEntity) {
+ private void updateCerInEntity(AaiEventEntity aaiEventEntity) {
try {
Map<String, List<String>> headers = new HashMap<>();
- headers.put(Headers.FROM_APP_ID, Arrays.asList("DataLayer"));
+ 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 = aaiEventEntity.getId();
+ 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);
+ searchClient.get(entitySearchTarget+entityId, headers, MediaType.APPLICATION_JSON_TYPE);
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.size() > 0) {
@@ -928,9 +973,34 @@ public class EntityEventPolicy implements Processor {
logger.error(EntityEventPolicyMsgs.NO_ETAG_AVAILABLE_FAILURE,
entitySearchTarget + entityId, entityId);
}
-
- searchClient.put(entitySearchTarget + entityId, aaiEventEntity.getAsJson(), headers,
- MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+
+ ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
+ 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 = aaiEventEntity.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);
+ searchClient.put(entitySearchTarget + entityId, jsonPayload, headers,
+ MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+ }
+ }
} else {
if (storedEntity.getResultCode() == 404) {
diff --git a/src/main/java/org/openecomp/datarouter/util/NodeUtils.java b/src/main/java/org/openecomp/datarouter/util/NodeUtils.java
index f957247..6b2044d 100644
--- a/src/main/java/org/openecomp/datarouter/util/NodeUtils.java
+++ b/src/main/java/org/openecomp/datarouter/util/NodeUtils.java
@@ -24,7 +24,17 @@
*/
package org.openecomp.datarouter.util;
+import java.io.IOException;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+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.SerializationFeature;
public class NodeUtils {
/**
@@ -43,4 +53,127 @@ public class NodeUtils {
return hashedId;
}
+
+ /**
+ * Extract field value from object.
+ *
+ * @param node the node
+ * @param fieldName the field name
+ * @return the string
+ */
+ public static String extractFieldValueFromObject(JsonNode node, String fieldName) {
+
+ if (node == null) {
+ return null;
+ }
+
+ if (node.isObject()) {
+
+ JsonNode valueNode = node.get(fieldName);
+
+ if (valueNode != null) {
+
+ if (valueNode.isValueNode()) {
+ return valueNode.asText();
+ }
+ }
+
+ }
+ return null;
+
+ }
+
+ /**
+ * Convert json str to json node.
+ *
+ * @param jsonStr the json str
+ * @return the json node
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static JsonNode convertJsonStrToJsonNode(String jsonStr) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ if (jsonStr == null || jsonStr.length() == 0) {
+ return null;
+ }
+
+ return mapper.readTree(jsonStr);
+ }
+
+ /**
+ * Extract objects by key.
+ *
+ * @param node the node
+ * @param searchKey the search key
+ * @param foundObjects the found objects
+ */
+ public static void extractObjectsByKey(JsonNode node, String searchKey,
+ Collection<JsonNode> foundObjects) {
+
+ if ( node == null ) {
+ return;
+ }
+
+ if (node.isObject()) {
+ Iterator<Map.Entry<String, JsonNode>> nodeIterator = node.fields();
+
+ while (nodeIterator.hasNext()) {
+ Map.Entry<String, JsonNode> entry = nodeIterator.next();
+ if (!entry.getValue().isValueNode()) {
+ extractObjectsByKey(entry.getValue(), searchKey, foundObjects);
+ }
+
+ String name = entry.getKey();
+ if (name.equalsIgnoreCase(searchKey)) {
+
+ JsonNode entryNode = entry.getValue();
+
+ if (entryNode.isArray()) {
+
+ Iterator<JsonNode> arrayItemsIterator = entryNode.elements();
+ while (arrayItemsIterator.hasNext()) {
+ foundObjects.add(arrayItemsIterator.next());
+ }
+
+ } else {
+ foundObjects.add(entry.getValue());
+ }
+
+
+ }
+ }
+ } else if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ while (arrayItemsIterator.hasNext()) {
+ extractObjectsByKey(arrayItemsIterator.next(), searchKey, foundObjects);
+ }
+
+ }
+
+ }
+
+ /**
+ * Convert object to json.
+ *
+ * @param object the object
+ * @param pretty the pretty
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ public static String convertObjectToJson(Object object, boolean pretty)
+ throws JsonProcessingException {
+ ObjectWriter ow = null;
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+
+ if (pretty) {
+ ow = mapper.writer().withDefaultPrettyPrinter();
+
+ } else {
+ ow = mapper.writer();
+ }
+
+ return ow.writeValueAsString(object);
+ }
+
}