summaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
authorda490c <dave.adams@amdocs.com>2018-03-08 12:54:22 -0500
committerda490c <dave.adams@amdocs.com>2018-03-08 12:59:30 -0500
commite5da3da7d7e0430a8d8d5c7c4a031c3ba557e247 (patch)
tree39a6272deea7c39d01820342e41f3923fe2f54fe /src/main/java
parent629fdccb42a58348b6a691ab736ba1600ea813a3 (diff)
Integrate Sparky-BE with Gizmo
Issue-ID: AAI-847 Change-Id: I8c61e681c4f427f6e567dd8498b6f5f7baa19c85 Signed-off-by: da490c <dave.adams@amdocs.com>
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java334
-rw-r--r--src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java93
-rw-r--r--src/main/java/org/onap/aai/sparky/util/NodeUtils.java104
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java47
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java40
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java96
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java101
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java75
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java988
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java23
-rw-r--r--src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java126
11 files changed, 1995 insertions, 32 deletions
diff --git a/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java b/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java
new file mode 100644
index 0000000..99a967c
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java
@@ -0,0 +1,334 @@
+/**
+ * ============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.sparky.dal;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+
+/**
+ * The Class GizmoAdapter.
+ */
+
+public class GizmoAdapter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(GizmoAdapter.class);
+
+ private static final String HEADER_TRANS_ID = "X-TransactionId";
+ private static final String HEADER_FROM_APP_ID = "X-FromAppId";
+ private static final String HEADER_AUTHORIZATION = "Authorization";
+
+ private static final String HTTP_SCHEME = "http";
+ private static final String HTTPS_SCHEME = "https";
+
+ private static final String TRANSACTION_ID_PREFIX = "txnId-";
+ private static final String UI_APP_NAME = "AAI-UI";
+
+ private OxmModelLoader oxmModelLoader;
+
+ private RestEndpointConfig endpointConfig;
+
+ private RestClient restClient;
+
+ private String inventoryBasePath;
+ private String relationshipsBasePath;
+
+ /**
+ * Instantiates a new active inventory adapter.
+ *
+ * @throws RestClientConstructionException
+ *
+ */
+
+ public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
+ throws ElasticSearchOperationException, IOException, RestClientConstructionException {
+
+ this.oxmModelLoader = oxmModelLoader;
+ this.endpointConfig = endpointConfig;
+ this.restClient = RestClientFactory.buildClient(endpointConfig);
+
+ }
+
+ public String getRelationshipsBasePath() {
+ return relationshipsBasePath;
+ }
+
+ public void setRelationshipsBasePath(String relationshipsBasePath) {
+ this.relationshipsBasePath = relationshipsBasePath;
+ }
+
+ public String getInventoryBasePath() {
+ return inventoryBasePath;
+ }
+
+ public void setInventoryBasePath(String inventoryBasePath) {
+ this.inventoryBasePath = inventoryBasePath;
+ }
+
+ public String getFullInventoryUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ final String basePath = getInventoryBasePath();
+ return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
+ }
+
+ public String addServerDetailsToUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ return String.format("https://%s:%s/%s", host, port, resourceUrl);
+ }
+
+ public String getFullRelationshipUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ final String basePath = getRelationshipsBasePath();
+ return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
+ }
+
+ protected Map<String, List<String>> getMessageHeaders() {
+
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+
+ headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
+ headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
+
+ headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
+ headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
+
+ if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+
+ headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
+ headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
+
+ }
+
+ return headers;
+ }
+
+ protected String getBasicAuthenticationCredentials() {
+ String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
+ endpointConfig.getBasicAuthPassword());
+ return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
+ }
+
+ /**
+ * Our retry conditions should be very specific.
+ *
+ * @param r
+ * the r
+ * @return true, if successful
+ */
+ private boolean shouldRetryRequest(OperationResult r) {
+
+ if (r == null) {
+ return true;
+ }
+
+ int rc = r.getResultCode();
+
+ if (rc == 200) {
+ return false;
+ }
+
+ if (rc == 404) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Query active inventory.
+ *
+ * @param url
+ * the url
+ * @param acceptContentType
+ * the accept content type
+ * @return the operation result
+ */
+ OperationResult queryGizmo(String url, String acceptContentType) {
+
+ return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
+
+ }
+
+ public RestEndpointConfig getEndpointConfig() {
+ return endpointConfig;
+ }
+
+ public void setEndpointConfig(RestEndpointConfig endpointConfig) {
+ this.endpointConfig = endpointConfig;
+ }
+
+ public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
+
+ OperationResult result = null;
+
+ for (int retryCount = 0; retryCount < numRetries; retryCount++) {
+
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
+
+ result = queryGizmo(url, responseType);
+
+ /**
+ * Record number of times we have attempted the request to later
+ * summarize how many times we are generally retrying over thousands
+ * of messages in a sync.
+ *
+ * If the number of retries is surprisingly high, then we need to
+ * understand why that is as the number of retries is also causing a
+ * heavier load on AAI beyond the throttling controls we already
+ * have in place in term of the transaction rate controller and
+ * number of parallelized threads per task processor.
+ */
+
+ result.setNumRetries(retryCount);
+
+ if (!shouldRetryRequest(result)) {
+
+ result.setFromCache(false);
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
+
+ return result;
+ }
+
+ try {
+ /*
+ * Sleep between re-tries to be nice to the target system.
+ */
+ Thread.sleep(50);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
+ break;
+ }
+ LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
+
+ }
+
+ LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
+
+ return result;
+
+ }
+
+ /**
+ * This method adds a scheme, host and port (if missing) to the passed-in
+ * URI. If these parts of the URI are already present, they will not be
+ * duplicated.
+ *
+ * @param selflink
+ * The URI to repair
+ * @param queryParams
+ * The query parameters as a single string
+ * @return The corrected URI (i.e. includes a scheme/host/port)
+ */
+
+ private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
+
+ if (selfLink == null) {
+ return selfLink;
+ }
+
+ if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
+ return selfLink;
+ }
+
+ UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
+ .host(endpointConfig.getEndpointIpAddress())
+ .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
+
+ switch (endpointConfig.getRestAuthenticationMode()) {
+
+ case SSL_BASIC:
+ case SSL_CERT: {
+ builder.scheme(HTTPS_SCHEME);
+ break;
+ }
+
+ default: {
+ builder.scheme(HTTP_SCHEME);
+ }
+ }
+
+ boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
+
+ /*
+ * builder.build().toString() will encode special characters to hexadecimal pairs prefixed with
+ * a '%' so we're adding the query parameters separately, in their UTF-8 representations, so
+ * that characters such as '?', '&', etc. remain intact as needed by the synchronizer
+ */
+ return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
+
+ }
+
+ public String repairRelationshipSelfLink(String selflink, String queryParams) {
+ return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
+ }
+
+ public String repairInventorySelfLink(String selflink, String queryParams) {
+ return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
+ }
+
+ public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
+
+ if (entityType == null) {
+ throw new NullPointerException("Failed to getSelfLinksByEntityType() because entityType is null");
+ }
+
+ String link = getFullInventoryUrl(entityType);
+
+ return queryGizmoWithRetries(link, "application/json", endpointConfig.getNumRequestRetries());
+
+ }
+
+ public static String extractResourcePath(String selflink) {
+ try {
+ return new URI(selflink).getRawPath();
+ } catch (URISyntaxException uriSyntaxException) {
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK, uriSyntaxException.getMessage());
+ return selflink;
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java b/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java
new file mode 100644
index 0000000..374163f
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java
@@ -0,0 +1,93 @@
+/**
+ * ============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.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.slf4j.MDC;
+
+/*
+ * Consider abstraction the tasks into common elemnts, because most of them repeat a generic call
+ * flow pattern
+ */
+
+/**
+ * The Class PerformActiveInventoryRetrieval.
+ */
+public class PerformGizmoRetrieval implements Supplier<NetworkTransaction> {
+
+ private static Logger logger = LoggerFactory.getInstance().getLogger(PerformGizmoRetrieval.class);
+
+ private NetworkTransaction txn;
+ private GizmoAdapter gizmoAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform active inventory retrieval.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ */
+ public PerformGizmoRetrieval(NetworkTransaction txn,
+ GizmoAdapter gizmoAdapter) {
+ this.txn = txn;
+ this.gizmoAdapter = gizmoAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+
+ txn.setTaskAgeInMs();
+
+ long startTimeInMs = System.currentTimeMillis();
+ MDC.setContextMap(contextMap);
+ OperationResult result = null;
+ try {
+ result = gizmoAdapter.queryGizmoWithRetries(txn.getLink(), "application/json", 5);
+ } catch (Exception exc) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC,"Failure to resolve self link from AAI. Error = " + exc.getMessage());
+ result = new OperationResult(500,
+ "Caught an exception while trying to resolve link = " + exc.getMessage());
+ } finally {
+ txn.setOperationResult(result);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ }
+
+ return txn;
+ }
+
+ protected void setContextMap(Map<String, String> contextMap) {
+ this.contextMap = contextMap;
+ }
+}
diff --git a/src/main/java/org/onap/aai/sparky/util/NodeUtils.java b/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
index 7657d7e..dd8e882 100644
--- a/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
+++ b/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
@@ -73,7 +73,9 @@ public class NodeUtils {
private static SecureRandom sRandom = new SecureRandom();
private static final Pattern AAI_VERSION_PREFIX = Pattern.compile("/aai/v[0-9]+/(.*)");
-
+ private static final Pattern GIZMO_VERSION_PREFIX = Pattern.compile("[/]*services/inventory/v[0-9]+/(.*)");
+ private static final Pattern GIZMO_RELATIONSHIP_VERSION_PREFIX = Pattern.compile("services/inventory/relationships/v[0-9]+/(.*)");
+
public static synchronized String getRandomTxnId(){
byte bytes[] = new byte[6];
@@ -119,6 +121,53 @@ public class NodeUtils {
return null;
}
+
+ public static String extractRawGizmoPathWithoutVersion(String resourceLink) {
+
+ try {
+
+ String rawPath = new URI(resourceLink).getRawPath();
+
+ Matcher m = GIZMO_VERSION_PREFIX.matcher(rawPath);
+
+ if (m.matches()) {
+
+ if ( m.groupCount() >= 1) {
+ return m.group(1);
+ }
+
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+
+ }
+
+ public static String extractRawGizmoRelationshipPathWithoutVersion(String resourceLink) {
+
+ try {
+
+ String rawPath = new URI(resourceLink).getRawPath();
+
+ Matcher m = GIZMO_RELATIONSHIP_VERSION_PREFIX.matcher(rawPath);
+
+ if (m.matches()) {
+
+ if ( m.groupCount() >= 1) {
+ return m.group(1);
+ }
+
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+
+ }
+
+
+
/**
* Checks if is numeric.
@@ -163,12 +212,7 @@ public class NodeUtils {
return Executors.newScheduledThreadPool(numWorkers + 1, namedThreadFactory);
}
- /**
- * Calculate edit attribute uri.
- *
- * @param link the link
- * @return the string
- */
+
public static String calculateEditAttributeUri(String link) {
String uri = null;
@@ -183,6 +227,7 @@ public class NodeUtils {
return uri;
}
+
/**
* Generate unique sha digest.
*
@@ -612,6 +657,51 @@ public class NodeUtils {
}
}
+ }
+
+ public static String extractObjectValueByKey(JsonNode node, String searchKey) {
+
+ if (node == null) {
+ return null;
+ }
+
+ 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()) {
+ return extractObjectValueByKey(entry.getValue(), searchKey);
+ }
+
+ String name = entry.getKey();
+ if (name.equalsIgnoreCase(searchKey)) {
+
+ JsonNode entryNode = entry.getValue();
+
+ if (entryNode.isArray()) {
+
+ Iterator<JsonNode> arrayItemsIterator = entryNode.elements();
+ while (arrayItemsIterator.hasNext()) {
+ return arrayItemsIterator.next().asText();
+ }
+
+ } else {
+ return entry.getValue().asText();
+ }
+
+
+ }
+ }
+ } else if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ while (arrayItemsIterator.hasNext()) {
+ return extractObjectValueByKey(arrayItemsIterator.next(), searchKey);
+ }
+
+ }
+
+ return null;
}
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java b/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
index a0be371..aff24bc 100644
--- a/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
@@ -46,11 +46,15 @@ public class VisualizationConfigs {
private boolean makeAllNeighborsBidirectional;
private ArrayList<String> shallowEntities;
+
+ private boolean gizmoEnabled;
/**
* Instantiates a new visualization config.
*/
- public VisualizationConfigs() {}
+ public VisualizationConfigs() {
+ this.gizmoEnabled = false;
+ }
public ArrayList<String> getShallowEntities() {
return shallowEntities;
@@ -129,23 +133,28 @@ public class VisualizationConfigs {
this.numOfThreadsToFetchNodeIntegrity = numOfThreadsToFetchNodeIntegrity;
}
-
-
- @Override
- public String toString() {
- return "VisualizationConfigs [maxSelfLinkTraversalDepth=" + maxSelfLinkTraversalDepth
- + ", visualizationDebugEnabled=" + visualizationDebugEnabled + ", "
- + (aaiEntityNodeDescriptors != null
- ? "aaiEntityNodeDescriptors=" + aaiEntityNodeDescriptors + ", " : "")
- + (generalNodeClassName != null ? "generalNodeClassName=" + generalNodeClassName + ", "
- : "")
- + (searchNodeClassName != null ? "searchNodeClassName=" + searchNodeClassName + ", " : "")
- + (selectedSearchedNodeClassName != null
- ? "selectedSearchedNodeClassName=" + selectedSearchedNodeClassName + ", " : "")
- + "numOfThreadsToFetchNodeIntegrity=" + numOfThreadsToFetchNodeIntegrity
- + ", makeAllNeighborsBidirectional=" + makeAllNeighborsBidirectional + "]";
- }
-
-
+ public boolean isGizmoEnabled() {
+ return gizmoEnabled;
+ }
+
+ public void setGizmoEnabled(boolean gizmoEnabled) {
+ this.gizmoEnabled = gizmoEnabled;
+ }
+
+ @Override
+ public String toString() {
+ return "VisualizationConfigs [maxSelfLinkTraversalDepth=" + maxSelfLinkTraversalDepth
+ + ", visualizationDebugEnabled=" + visualizationDebugEnabled + ", "
+ + (aaiEntityNodeDescriptors != null ? "aaiEntityNodeDescriptors=" + aaiEntityNodeDescriptors + ", "
+ : "")
+ + (generalNodeClassName != null ? "generalNodeClassName=" + generalNodeClassName + ", " : "")
+ + (searchNodeClassName != null ? "searchNodeClassName=" + searchNodeClassName + ", " : "")
+ + (selectedSearchedNodeClassName != null
+ ? "selectedSearchedNodeClassName=" + selectedSearchedNodeClassName + ", " : "")
+ + "numOfThreadsToFetchNodeIntegrity=" + numOfThreadsToFetchNodeIntegrity
+ + ", makeAllNeighborsBidirectional=" + makeAllNeighborsBidirectional + ", "
+ + (shallowEntities != null ? "shallowEntities=" + shallowEntities + ", " : "") + "gizmoEnabled="
+ + gizmoEnabled + "]";
+ }
}
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
index c5d9b4a..e90d469 100644
--- a/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
@@ -66,6 +66,10 @@ public class ActiveInventoryNode {
private boolean isRootNode;
private ConcurrentLinkedDeque<String> inboundNeighbors;
private ConcurrentLinkedDeque<String> outboundNeighbors;
+
+ private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
+ private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
+
private List<JsonNode> complexGroups;
private List<RelationshipList> relationshipLists;
private int nodeDepth;
@@ -139,6 +143,10 @@ public class ActiveInventoryNode {
isRootNode = false;
inboundNeighbors = new ConcurrentLinkedDeque<String>();
outboundNeighbors = new ConcurrentLinkedDeque<String>();
+
+ inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
+ outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
+
complexGroups = new ArrayList<JsonNode>();
relationshipLists = new ArrayList<RelationshipList>();
nodeDepth = DEFAULT_INIT_NODE_DEPTH;
@@ -164,6 +172,38 @@ public class ActiveInventoryNode {
}
}
+ public void addInboundSelfLink(String link) {
+
+ if (link == null) {
+ return;
+ }
+
+ if (!inboundNeighborSelfLinks.contains(link)) {
+ inboundNeighborSelfLinks.add(link);
+ }
+
+ }
+
+ public void addOutboundSelfLink(String link) {
+
+ if (link == null) {
+ return;
+ }
+
+ if (!outboundNeighborSelfLinks.contains(link)) {
+ outboundNeighborSelfLinks.add(link);
+ }
+
+ }
+
+ public Collection<String> getInboundNeighborSelfLinks() {
+ return inboundNeighborSelfLinks;
+ }
+
+ public Collection<String> getOutboundNeighborSelfLinks() {
+ return outboundNeighborSelfLinks;
+ }
+
public void addQueryParams(Collection<String> params) {
if (params != null & params.size() > 0) {
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java
new file mode 100644
index 0000000..211efa5
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java
@@ -0,0 +1,96 @@
+/**
+ * ============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.sparky.viewandinspect.entity;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public class GizmoEntity {
+
+ private String id;
+ private String type;
+ private String url;
+ private Map<String, String> properties;
+ private GizmoRelationshipHint[] in;
+ private GizmoRelationshipHint[] out;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, String> properties) {
+ this.properties = properties;
+ }
+
+ public GizmoRelationshipHint[] getIn() {
+ return in;
+ }
+
+ public void setIn(GizmoRelationshipHint[] in) {
+ this.in = in;
+ }
+
+ public GizmoRelationshipHint[] getOut() {
+ return out;
+ }
+
+ public void setOut(GizmoRelationshipHint[] out) {
+ this.out = out;
+ }
+
+ @Override
+ public String toString() {
+ return "GizmoEntity [" + (id != null ? "id=" + id + ", " : "")
+ + (type != null ? "type=" + type + ", " : "") + (url != null ? "url=" + url + ", " : "")
+ + (properties != null ? "properties=" + properties + ", " : "")
+ + (in != null ? "in=" + Arrays.toString(in) + ", " : "")
+ + (out != null ? "out=" + Arrays.toString(out) : "") + "]";
+ }
+
+
+
+}
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java
new file mode 100644
index 0000000..a566d69
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java
@@ -0,0 +1,101 @@
+/**
+ * ============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.sparky.viewandinspect.entity;
+
+import java.util.Map;
+
+public class GizmoRelationshipEntity {
+
+ /*
+ * {"id":"oe4ur-3a0-27th-fu8","type":"has","url":
+ * "services/inventory/relationships/v8/has/oe4ur-3a0-27th-fu8","source":
+ * "services/inventory/v8/generic-vnf/4248","target":
+ * "services/inventory/v8/vserver/20528",
+ * "properties":{"is-parent":"true","multiplicity":"many","has-del-target":
+ * "true","uses-resource": "true"}}
+ */
+
+ private String id;
+ private String type;
+ private String url;
+ private String source;
+ private String target;
+ private Map<String, String> properties;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, String> properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public String toString() {
+ return "GizmoRelationshipEntity [" + (id != null ? "id=" + id + ", " : "")
+ + (type != null ? "type=" + type + ", " : "") + (url != null ? "url=" + url + ", " : "")
+ + (source != null ? "source=" + source + ", " : "") + (target != null ? "target=" + target + ", " : "")
+ + (properties != null ? "properties=" + properties : "") + "]";
+ }
+
+}
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java
new file mode 100644
index 0000000..f28ba5b
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java
@@ -0,0 +1,75 @@
+/**
+ * ============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.sparky.viewandinspect.entity;
+
+public class GizmoRelationshipHint {
+
+ private String id;
+ private String type;
+ private String url;
+ private String source;
+ private String target;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+
+
+ }
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java b/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java
new file mode 100644
index 0000000..8963ff7
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java
@@ -0,0 +1,988 @@
+/**
+ * ============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.sparky.viewandinspect.services;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoEntity;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipEntity;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipHint;
+import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+import org.onap.aai.sparky.viewandinspect.task.PerformGizmoNodeSelfLinkProcessingTask;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+
+/**
+ * The Class SelfLinkNodeCollector.
+ */
+public class BaseGizmoVisualizationContext implements VisualizationContext {
+
+ private static final int MAX_DEPTH_EVALUATION_ATTEMPTS = 100;
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(BaseGizmoVisualizationContext.class);
+
+ private final GizmoAdapter gizmoAdapter;
+
+ private AtomicInteger numLinksDiscovered;
+ private AtomicInteger numSuccessfulLinkResolveFromCache;
+ private AtomicInteger numSuccessfulLinkResolveFromFromServer;
+ private AtomicInteger numFailedLinkResolve;
+ private AtomicInteger aaiWorkOnHand;
+
+ private VisualizationConfigs visualizationConfigs;
+
+ private AtomicInteger totalLinksRetrieved;
+
+ private final long contextId;
+ private final String contextIdStr;
+ private long lastProcessStatesSummaryLogInMs = -1;
+
+
+ private ObjectMapper mapper;
+ private InlineMessage inlineMessage = null;
+
+ private ExecutorService graphExecutorService;
+ private OxmEntityLookup oxmEntityLookup;
+ private boolean rootNodeFound;
+
+ /*
+ * The node cache is intended to be a flat structure indexed by a primary key to avoid needlessly
+ * re-requesting the same self-links over-and-over again, to speed up the overall render time and
+ * more importantly to reduce the network cost of determining information we already have.
+ */
+ private ConcurrentHashMap<String, ActiveInventoryNode> nodeCache;
+
+ /**
+ * Instantiates a new self link node collector.
+ *
+ * @param loader the loader
+ * @throws Exception the exception
+ */
+ public BaseGizmoVisualizationContext(long contextId, GizmoAdapter gizmoAdapter,
+ ExecutorService graphExecutorService, VisualizationConfigs visualizationConfigs,
+ OxmEntityLookup oxmEntityLookup) throws Exception {
+
+ this.contextId = contextId;
+ this.contextIdStr = "[Context-Id=" + contextId + "]";
+ this.gizmoAdapter = gizmoAdapter;
+ this.graphExecutorService = graphExecutorService;
+ this.visualizationConfigs = visualizationConfigs;
+ this.oxmEntityLookup = oxmEntityLookup;
+
+ this.nodeCache = new ConcurrentHashMap<String, ActiveInventoryNode>();
+ this.numLinksDiscovered = new AtomicInteger(0);
+ this.totalLinksRetrieved = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromCache = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromFromServer = new AtomicInteger(0);
+ this.numFailedLinkResolve = new AtomicInteger(0);
+ this.aaiWorkOnHand = new AtomicInteger(0);
+
+ this.mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Include.NON_EMPTY);
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
+ this.rootNodeFound = false;
+ }
+
+ protected boolean isRootNodeFound() {
+ return rootNodeFound;
+ }
+
+ protected void setRootNodeFound(boolean rootNodeFound) {
+ this.rootNodeFound = rootNodeFound;
+ }
+
+ public long getContextId() {
+ return contextId;
+ }
+
+ public GizmoAdapter getGizmoAdapter() {
+ return gizmoAdapter;
+ }
+
+ /**
+ * Process self link response.
+ *
+ * @param nodeId the node id
+ */
+ private void processSelfLinkResponse(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Cannot process self link" + " response because nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Cannot process self link response" + " because can't find node for id = " + nodeId);
+ return;
+ }
+
+ GizmoEntity gizmoEntity = null;
+
+ try {
+ gizmoEntity = mapper.readValue(ain.getOpResult().getResult(), GizmoEntity.class);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to marshal json"
+ + " response str into JsonNode with error, " + exc.getLocalizedMessage());
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ if (gizmoEntity == null) {
+
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR,
+ "Failed to parse json node str." + " Parse resulted a null value.");
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ /*
+ * Now that we have the gizmo entity we can populate the AIN node with it, as well as the
+ * relationships
+ */
+
+ ain.setEntityType(gizmoEntity.getType());
+
+ ain.setPrimaryKeyName(getEntityTypePrimaryKeyName(gizmoEntity.getType()));
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(gizmoEntity);
+
+ if (descriptor != null) {
+ ain.setPrimaryKeyValue(getPrimaryKeyValues(gizmoEntity.getProperties(),
+ descriptor.getPrimaryKeyAttributeNames()));
+ } else {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Could not determine oxm descriptor for entity type = " + gizmoEntity.getType());
+ }
+
+ gizmoEntity.getProperties().forEach((key, value) -> {
+ ain.getProperties().put(key, value);
+ });
+
+ // add edit attributes link
+ if (ain.getSelfLink() != null) {
+ ain.addProperty(SparkyConstants.URI_ATTR_NAME, ain.getSelfLink());
+ }
+
+
+
+ /*
+ * Only discover neighbors if our depth is less than the Max-Traversal-Depth
+ */
+
+ if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
+
+ /*
+ * I think the next thing to do is:
+ *
+ * 1. Calculate the source / target node id 2. Add the nodeId to the incoming / outgoing links
+ * collection 3. Add the node to the node cache for processing
+ */
+
+ String resourceLink = null;
+ String relationshipNodeId = null;
+ ActiveInventoryNode relationshipNode = null;
+
+ for (GizmoRelationshipHint inRelationship : gizmoEntity.getIn()) {
+
+ if (inRelationship.getSource() != null) {
+
+ resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(inRelationship.getSource());
+ relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
+
+ if (!nodeCache.containsKey(relationshipNodeId)) {
+
+ relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
+ relationshipNode.setNodeId(relationshipNodeId);
+ relationshipNode.setSelfLink(resourceLink);
+ relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.NEW_NODE_PROCESSED);
+
+ ain.addInboundNeighbor(relationshipNodeId);
+
+ addNode(relationshipNode);
+
+ }
+ }
+
+ }
+
+ for (GizmoRelationshipHint outRelationship : gizmoEntity.getOut()) {
+
+ if (outRelationship.getTarget() != null) {
+
+ resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(outRelationship.getTarget());
+ relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
+
+ if (!nodeCache.containsKey(relationshipNodeId)) {
+
+ relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
+ relationshipNode.setNodeId(relationshipNodeId);
+ relationshipNode.setSelfLink(resourceLink);
+ relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.NEW_NODE_PROCESSED);
+
+ ain.addOutboundNeighbor(relationshipNodeId);
+
+ addNode(relationshipNode);
+
+ }
+ }
+
+ }
+ }
+
+ ain.changeState(NodeProcessingState.READY, NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ }
+
+ /**
+ * Perform self link resolve.
+ *
+ * @param nodeId the node id
+ */
+ private void performSelfLinkResolve(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Resolve of self-link" + " has been skipped because provided nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Failed to find node with id, " + nodeId
+ + ", from node cache. Resolve self-link method has been skipped.");
+ return;
+ }
+
+ if (!ain.isSelfLinkPendingResolve()) {
+
+ ain.setSelfLinkPendingResolve(true);
+
+ // kick off async self-link resolution
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "About to process node in SELF_LINK_UNPROCESSED State, link = " + ain.getSelfLink());
+ }
+
+ numLinksDiscovered.incrementAndGet();
+
+ /*
+ * If the current node is the search target, we want to see everything the node has to offer
+ * from the self-link and not filter it to a single node.
+ */
+
+ NodeProcessingTransaction txn = new NodeProcessingTransaction();
+ txn.setProcessingNode(ain);
+ txn.setRequestParameters(null);
+ aaiWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformGizmoNodeSelfLinkProcessingTask(txn, null, gizmoAdapter),
+ graphExecutorService).whenComplete((nodeTxn, error) -> {
+
+ if (error != null) {
+
+ /*
+ * an error processing the self link should probably result in the node processing
+ * state shifting to ERROR
+ */
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+
+ totalLinksRetrieved.incrementAndGet();
+
+ OperationResult opResult = nodeTxn.getOpResult();
+
+ if (opResult != null && opResult.wasSuccessful()) {
+
+ if (!opResult.wasSuccessful()) {
+ numFailedLinkResolve.incrementAndGet();
+ }
+
+ if (opResult.isFromCache()) {
+ numSuccessfulLinkResolveFromCache.incrementAndGet();
+ } else {
+ numSuccessfulLinkResolveFromFromServer.incrementAndGet();
+ }
+
+ // success path
+ nodeTxn.getProcessingNode().setOpResult(opResult);
+ nodeTxn.getProcessingNode().changeState(
+ NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESOLVE_OK);
+
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Self Link retrieval for link," + txn.getSelfLinkWithModifiers()
+ + ", failed with error code," + nodeTxn.getOpResult().getResultCode()
+ + ", and message," + nodeTxn.getOpResult().getResult());
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ }
+ }
+
+ aaiWorkOnHand.decrementAndGet();
+
+ });
+
+ }
+
+ }
+
+ public GizmoRelationshipEntity getGizmoRelationshipEntity(String gizmoJsonResponse) {
+
+ GizmoRelationshipEntity gizmoRelationship = null;
+ try {
+ gizmoRelationship = mapper.readValue(gizmoJsonResponse, GizmoRelationshipEntity.class);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to map json to GizmoRelationshipEntity. Error: " + exc.getMessage());
+ }
+
+ return gizmoRelationship;
+
+ }
+
+ public String getPrimaryKeyValues(Map<String, String> properties, List<String> pkeyNames) {
+
+ StringBuilder sb = new StringBuilder(64);
+
+ if (pkeyNames.size() > 0) {
+ String primaryKey = properties.get(pkeyNames.get(0));
+ if (primaryKey != null) {
+ sb.append(primaryKey);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract" + " keyName, "
+ + pkeyNames.get(0) + ", from properties , " + properties);
+ return null;
+ }
+
+ for (int i = 1; i < pkeyNames.size(); i++) {
+
+ String kv = properties.get(pkeyNames.get(i));
+ if (kv != null) {
+ sb.append("/").append(kv);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: failed to extract keyName, "
+ + pkeyNames.get(i) + ", from properties, " + properties);
+ return null;
+ }
+ }
+
+ return sb.toString();
+
+ }
+
+ return null;
+
+ }
+
+
+
+ /**
+ * Find and mark root node.
+ *
+ * @param queryParams the query params
+ * @return true, if successful
+ */
+ private void findAndMarkRootNode(QueryParams queryParams) {
+
+ if (isRootNodeFound()) {
+ return;
+ }
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (queryParams.getSearchTargetNodeId().equals(cacheNode.getNodeId())) {
+ cacheNode.setNodeDepth(0);
+ cacheNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+ }
+ }
+
+ }
+
+ public void addNode(ActiveInventoryNode node) {
+
+ if (node == null) {
+ return;
+ }
+
+ nodeCache.putIfAbsent(node.getNodeId(), node);
+ }
+
+ public VisualizationConfigs getVisualizationConfigs() {
+ return visualizationConfigs;
+ }
+
+ public void setVisualizationConfigs(VisualizationConfigs visualizationConfigs) {
+ this.visualizationConfigs = visualizationConfigs;
+ }
+
+ public OxmEntityLookup getOxmEntityLookup() {
+ return oxmEntityLookup;
+ }
+
+ public void setOxmEntityLookup(OxmEntityLookup oxmEntityLookup) {
+ this.oxmEntityLookup = oxmEntityLookup;
+ }
+
+ public ObjectMapper getMapper() {
+ return mapper;
+ }
+
+ public void setMapper(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ private void dumpThrottledWorkOnHandLog() {
+ dumpThrottledWorkOnHandLog(false);
+ }
+
+ private void dumpThrottledWorkOnHandLog(boolean override) {
+
+ if ((lastProcessStatesSummaryLogInMs < 0)
+ || ((System.currentTimeMillis() > (lastProcessStatesSummaryLogInMs + 5000))) || override) {
+
+ lastProcessStatesSummaryLogInMs = System.currentTimeMillis();
+
+ int numInit = 0;
+ int numReady = 0;
+ int numError = 0;
+ int numSelfLinkUnresolved = 0;
+ int numSelfLinkResponseUnprocessed = 0;
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ switch (cacheNode.getState()) {
+
+ case INIT: {
+ numInit++;
+ break;
+ }
+
+ case READY: {
+ numReady++;
+ break;
+ }
+ case ERROR: {
+ numError++;
+ break;
+ }
+
+ case SELF_LINK_UNRESOLVED: {
+ numSelfLinkUnresolved++;
+ break;
+ }
+
+ case SELF_LINK_RESPONSE_UNPROCESSED: {
+ numSelfLinkResponseUnprocessed++;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ String.format(
+ "ProcessCurrentStates for ContextId=%s, [PendingTxns=%d, numInit=%d, numSelfLinkUnresolved=%d, numSelfLinkResponseUnProcessed=%d, numReady=%d, numError=%d]",
+ contextIdStr, aaiWorkOnHand.get(), numInit, numSelfLinkUnresolved, numSelfLinkResponseUnprocessed,
+ numReady, numError));
+ }
+
+ }
+
+ /**
+ * Process current node states.
+ *
+ * @param rootNodeDiscovered the root node discovered
+ */
+ private void processCurrentNodeStates(QueryParams queryParams) {
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ findAndMarkRootNode(queryParams);
+
+ verifyOutboundNeighbors();
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "processCurrentNodeState(), nid = "
+ + cacheNode.getNodeId() + " , nodeDepth = " + cacheNode.getNodeDepth());
+ }
+
+ switch (cacheNode.getState()) {
+
+ case INIT: {
+ processInitialState(cacheNode.getNodeId());
+ break;
+ }
+
+ case READY:
+ case ERROR: {
+ break;
+ }
+
+ case SELF_LINK_UNRESOLVED: {
+ performSelfLinkResolve(cacheNode.getNodeId());
+ break;
+ }
+
+ case SELF_LINK_RESPONSE_UNPROCESSED: {
+ processSelfLinkResponse(cacheNode.getNodeId());
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ dumpThrottledWorkOnHandLog();
+
+ }
+
+
+
+ public int getNumSuccessfulLinkResolveFromCache() {
+ return numSuccessfulLinkResolveFromCache.get();
+ }
+
+ public int getNumSuccessfulLinkResolveFromFromServer() {
+ return numSuccessfulLinkResolveFromFromServer.get();
+ }
+
+ public int getNumFailedLinkResolve() {
+ return numFailedLinkResolve.get();
+ }
+
+ public InlineMessage getInlineMessage() {
+ return inlineMessage;
+ }
+
+ public void setInlineMessage(InlineMessage inlineMessage) {
+ this.inlineMessage = inlineMessage;
+ }
+
+ public ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache() {
+ return nodeCache;
+ }
+
+
+
+ /**
+ * Process initial state.
+ *
+ * @param nodeId the node id
+ */
+ private void processInitialState(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE, "Node id is null");
+ return;
+ }
+
+ ActiveInventoryNode cachedNode = nodeCache.get(nodeId);
+
+ if (cachedNode == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE,
+ "Node cannot be" + " found for nodeId, " + nodeId);
+ return;
+ }
+
+ if (cachedNode.getSelfLink() == null) {
+
+ if (cachedNode.getNodeId() == null) {
+
+ /*
+ * if the self link is null at the INIT state, which could be valid if this node is a
+ * complex attribute group which didn't originate from a self-link, but in that situation
+ * both the node id and node key should already be set.
+ */
+
+ cachedNode.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NODE_IDENTITY_ERROR);
+
+ }
+
+ if (cachedNode.getNodeId() != null) {
+
+ /*
+ * This should be the success path branch if the self-link is not set
+ */
+
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ }
+
+ } else {
+
+ if (cachedNode.hasResolvedSelfLink()) {
+ LOG.error(AaiUiMsgs.INVALID_RESOLVE_STATE_DURING_INIT);
+ cachedNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.UNEXPECTED_STATE_TRANSITION);
+ } else {
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.SELF_LINK_SET);
+ }
+ }
+ }
+
+ /**
+ * Process skeleton node.
+ *
+ * @param skeletonNode the skeleton node
+ * @param queryParams the query params
+ */
+ private void processSearchableEntity(SearchableEntity searchTargetEntity,
+ QueryParams queryParams) {
+
+ if (searchTargetEntity == null) {
+ return;
+ }
+
+ if (searchTargetEntity.getId() == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_SKELETON_NODE, "Failed to process skeleton"
+ + " node because nodeId is null for node, " + searchTargetEntity.getLink());
+ return;
+ }
+
+ ActiveInventoryNode newNode =
+ new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
+
+ newNode.setNodeId(searchTargetEntity.getId());
+
+ newNode.setNodeDepth(0);
+ newNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+
+ newNode.setSelfLink(searchTargetEntity.getLink());
+
+ nodeCache.putIfAbsent(newNode.getNodeId(), newNode);
+ }
+
+ private int getTotalWorkOnHand() {
+
+ int numNodesWithPendingStates = 0;
+
+ if (isRootNodeFound()) {
+ evaluateNodeDepths();
+ }
+
+ for (ActiveInventoryNode n : nodeCache.values()) {
+
+ switch (n.getState()) {
+
+ case READY:
+ case ERROR: {
+ // do nothing, these are our normal
+ // exit states
+ break;
+ }
+
+ default: {
+
+ /*
+ * for all other states, there is work to be done
+ */
+ numNodesWithPendingStates++;
+ }
+
+ }
+
+ }
+
+ return (aaiWorkOnHand.get() + numNodesWithPendingStates);
+
+ }
+
+ /**
+ * Checks for out standing work.
+ *
+ * @return true, if successful
+ */
+ private void processOutstandingWork(QueryParams queryParams) {
+
+ while (getTotalWorkOnHand() > 0) {
+
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ processCurrentNodeStates(queryParams);
+
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.PROCESSING_LOOP_INTERUPTED, exc.getMessage());
+ return;
+ }
+
+ }
+
+ dumpThrottledWorkOnHandLog(true);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.aai.sparky.viewandinspect.services.VisualizationContext#processSelfLinks(org.onap.aai.
+ * sparky.sync.entity.SearchableEntity, org.onap.aai.sparky.viewandinspect.entity.QueryParams)
+ */
+ @Override
+ public void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams) {
+
+ try {
+
+
+ if (searchtargetEntity == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ contextIdStr + " - Failed to" + " processSelfLinks, searchtargetEntity is null");
+ return;
+ }
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ processSearchableEntity(searchtargetEntity, queryParams);
+
+ /*
+ * This method is blocking until we decouple it with a CountDownLatch await condition, and
+ * make the internal graph processing more event-y.
+ */
+
+ processOutstandingWork(queryParams);
+
+ long totalResolveTime = (System.currentTimeMillis() - startTimeInMs);
+
+ long opTime = System.currentTimeMillis() - startTimeInMs;
+
+ LOG.info(AaiUiMsgs.ALL_TRANSACTIONS_RESOLVED, String.valueOf(totalResolveTime),
+ String.valueOf(totalLinksRetrieved.get()), String.valueOf(opTime));
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR, exc.getMessage());
+ }
+
+ }
+
+ /**
+ * Verify outbound neighbors.
+ */
+ private void verifyOutboundNeighbors() {
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null && srcNode.getNodeId() != null) {
+
+ targetNode.addInboundNeighbor(srcNode.getNodeId());
+
+ if (this.visualizationConfigs.makeAllNeighborsBidirectional()) {
+ targetNode.addOutboundNeighbor(srcNode.getNodeId());
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Evaluate node depths.
+ */
+ private void evaluateNodeDepths() {
+
+ int numChanged = -1;
+ int numAttempts = 0;
+
+ while (numChanged != 0) {
+
+ numChanged = 0;
+ numAttempts++;
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ if (srcNode.getState() == NodeProcessingState.INIT) {
+
+ /*
+ * this maybe the only state that we don't want to to process the node depth on, because
+ * typically it won't have any valid fields set, and it may remain in a partial state
+ * until we have processed the self-link.
+ */
+
+ continue;
+
+ }
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+
+ for (String targetNodeId : srcNode.getInboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+ }
+
+ if (numAttempts >= MAX_DEPTH_EVALUATION_ATTEMPTS) {
+ LOG.info(AaiUiMsgs.MAX_EVALUATION_ATTEMPTS_EXCEEDED);
+ return;
+ }
+
+ }
+
+ if (LOG.isDebugEnabled()) {
+ if (numAttempts > 0) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in " + numAttempts + " attempts");
+ } else {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in 0 attempts because all nodes at correct depth");
+ }
+ }
+
+ }
+
+
+ /**
+ * Gets the entity type primary key name.
+ *
+ * @param entityType the entity type
+ * @return the entity type primary key name
+ */
+
+
+ private String getEntityTypePrimaryKeyName(String entityType) {
+
+ if (entityType == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "node primary key" + " name because entity type is null");
+ return null;
+ }
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "oxm entity" + " descriptor for entityType = " + entityType);
+ return null;
+ }
+
+ List<String> pkeyNames = descriptor.getPrimaryKeyAttributeNames();
+
+ if (pkeyNames == null || pkeyNames.size() == 0) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "node primary" + " key because descriptor primary key names is empty");
+ return null;
+ }
+
+ return NodeUtils.concatArray(pkeyNames, "/");
+
+ }
+
+}
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java b/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
index ed5ec8d..9c3c7da 100644
--- a/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
@@ -37,6 +37,7 @@ import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
import org.onap.aai.sparky.config.oxm.OxmModelLoader;
import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.GizmoAdapter;
import org.onap.aai.sparky.logging.AaiUiMsgs;
import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
@@ -64,6 +65,7 @@ public class BaseVisualizationService implements VisualizationService {
private ObjectMapper mapper = new ObjectMapper();
private final ActiveInventoryAdapter aaiAdapter;
+ private final GizmoAdapter gizmoAdapter;
private final ElasticSearchAdapter esAdapter;
private final ExecutorService aaiExecutorService;
@@ -76,16 +78,18 @@ public class BaseVisualizationService implements VisualizationService {
private ElasticSearchSchemaConfig schemaEConfig;
private OxmEntityLookup oxmEntityLookup;
- public BaseVisualizationService(OxmModelLoader loader, VisualizationConfigs visualizationConfigs,
- ActiveInventoryAdapter aaiAdapter,ElasticSearchAdapter esAdapter,
- ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig, int numActiveInventoryWorkers,
- OxmEntityLookup oxmEntityLookup, SubscriptionConfig subscriptionConfig) throws Exception {
+ public BaseVisualizationService(OxmModelLoader loader, VisualizationConfigs visualizationConfigs,
+ ActiveInventoryAdapter aaiAdapter, GizmoAdapter gizmoAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig,
+ int numActiveInventoryWorkers, OxmEntityLookup oxmEntityLookup, SubscriptionConfig subscriptionConfig)
+ throws Exception {
this.visualizationConfigs = visualizationConfigs;
this.endpointEConfig = endpointConfig;
this.schemaEConfig = schemaConfig;
this.oxmEntityLookup = oxmEntityLookup;
this.subConfig = subscriptionConfig;
+
secureRandom = new SecureRandom();
@@ -94,6 +98,7 @@ public class BaseVisualizationService implements VisualizationService {
*/
this.aaiAdapter = aaiAdapter;
+ this.gizmoAdapter = gizmoAdapter;
this.esAdapter = esAdapter;
this.mapper = new ObjectMapper();
@@ -276,8 +281,14 @@ public class BaseVisualizationService implements VisualizationService {
VisualizationContext visContext = null;
long contextId = secureRandom.nextLong();
try {
- visContext = new BaseVisualizationContext(contextId, this.aaiAdapter, aaiExecutorService,
- this.visualizationConfigs, oxmEntityLookup);
+ if ( visualizationConfigs.isGizmoEnabled()) {
+ visContext = new BaseGizmoVisualizationContext(contextId, this.gizmoAdapter, aaiExecutorService,
+ this.visualizationConfigs, oxmEntityLookup);
+ } else {
+ visContext = new BaseVisualizationContext(contextId, this.aaiAdapter, aaiExecutorService,
+ this.visualizationConfigs, oxmEntityLookup);
+ }
+
contextMap.putIfAbsent(contextId, visContext);
} catch (Exception e1) {
LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT,
diff --git a/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java b/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java
new file mode 100644
index 0000000..bccd7aa
--- /dev/null
+++ b/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java
@@ -0,0 +1,126 @@
+/**
+ * ============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.sparky.viewandinspect.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformNodeSelfLinkProcessingTask.
+ */
+public class PerformGizmoNodeSelfLinkProcessingTask implements Supplier<NodeProcessingTransaction> {
+
+ private static final Logger logger =
+ LoggerFactory.getInstance().getLogger(PerformGizmoNodeSelfLinkProcessingTask.class);
+
+ private NodeProcessingTransaction txn;
+ private GizmoAdapter gizmoAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform node self link processing task.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ * @param aaiConfig the aai config
+ */
+ /**
+ *
+ * @param txn
+ * @param requestParameters
+ * @param aaiProvider
+ * @param aaiConfig
+ */
+ public PerformGizmoNodeSelfLinkProcessingTask(NodeProcessingTransaction txn, String requestParameters,
+ GizmoAdapter gizmoAdapter) {
+ this.gizmoAdapter = gizmoAdapter;
+ this.txn = txn;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NodeProcessingTransaction get() {
+ MDC.setContextMap(contextMap);
+ OperationResult opResult = new OperationResult();
+ String link = txn.getSelfLink();
+
+ if (link == null) {
+ opResult.setResult(500, "Aborting self-link processing because self link is null");
+ txn.setOpResult(opResult);
+ return txn;
+ }
+
+ /**
+ * Rebuild the self link:
+ *
+ * <li>build the base url with the configured scheme + authority (server:port)
+ * <li>recombine baseUrl + originalEncodedLink + queryStringParameters
+ *
+ */
+
+ final String urlSchemeAndAuthority = gizmoAdapter.repairInventorySelfLink("", null);
+
+ String parameters = txn.getRequestParameters();
+ link = urlSchemeAndAuthority + link;
+
+ if (parameters != null) {
+ link += parameters;
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Collecting " + link);
+ }
+
+ try {
+
+ opResult = gizmoAdapter.queryGizmoWithRetries(link, "application/json",
+ gizmoAdapter.getEndpointConfig().getNumRequestRetries());
+ } catch (Exception exc) {
+ opResult = new OperationResult();
+ opResult.setResult(500, "Querying AAI with retry failed due to an exception.");
+ logger.error(AaiUiMsgs.ERROR_AAI_QUERY_WITH_RETRY, exc.getMessage());
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Operation result = " + opResult.toString());
+ }
+
+ txn.setOpResult(opResult);
+ return txn;
+
+ }
+
+}