* ============LICENSE_START=======================================================
* org.onap.aai
* ================================================================================
- * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
- * Copyright © 2017 Amdocs
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 Amdocs
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.http.client.utils.URIBuilder;
-import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
-import org.onap.aai.sparky.config.oxm.OxmModelLoader;
-import org.onap.aai.sparky.dal.aai.ActiveInventoryDataProvider;
-import org.onap.aai.sparky.dal.aai.config.ActiveInventoryConfig;
-import org.onap.aai.sparky.dal.rest.OperationResult;
-import org.onap.aai.sparky.logging.AaiUiMsgs;
-import org.onap.aai.sparky.synchronizer.entity.SearchableEntity;
-import org.onap.aai.sparky.util.NodeUtils;
-import org.onap.aai.sparky.viewandinspect.config.TierSupportUiConstants;
-import org.onap.aai.sparky.viewandinspect.config.VisualizationConfig;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
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.entity.Relationship;
-import org.onap.aai.sparky.viewandinspect.entity.RelationshipData;
-import org.onap.aai.sparky.viewandinspect.entity.RelationshipList;
-import org.onap.aai.sparky.viewandinspect.entity.SelfLinkDeterminationTransaction;
-import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
-import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
-import org.onap.aai.sparky.viewandinspect.task.PerformNodeSelfLinkProcessingTask;
-import org.onap.aai.sparky.viewandinspect.task.PerformSelfLinkDeterminationTask;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
-
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.PropertyNamingStrategy;
-
-/**
- * The Class SelfLinkNodeCollector.
- */
-public class VisualizationContext {
-
- private static final int MAX_DEPTH_EVALUATION_ATTEMPTS = 100;
- private static final String DEPTH_ALL_MODIFIER = "?depth=all";
- private static final String NODES_ONLY_MODIFIER = "?nodes-only";
- private static final String SERVICE_INSTANCE = "service-instance";
-
- private static final Logger LOG = LoggerFactory.getInstance().getLogger(
- VisualizationContext.class);
- private final ActiveInventoryDataProvider aaiProvider;
-
- private int maxSelfLinkTraversalDepth;
- private AtomicInteger numLinksDiscovered;
- private AtomicInteger numSuccessfulLinkResolveFromCache;
- private AtomicInteger numSuccessfulLinkResolveFromFromServer;
- private AtomicInteger numFailedLinkResolve;
- private AtomicInteger aaiWorkOnHand;
-
- private ActiveInventoryConfig aaiConfig;
- private VisualizationConfig visualizationConfig;
- private List<String> shallowEntities;
-
- private AtomicInteger totalLinksRetrieved;
-
- private final long contextId;
- private final String contextIdStr;
-
- private OxmModelLoader loader;
- private ObjectMapper mapper;
- private InlineMessage inlineMessage = null;
-
- private ExecutorService aaiExecutorService;
-
- /*
- * 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 VisualizationContext(long contextId, ActiveInventoryDataProvider aaiDataProvider,
- ExecutorService aaiExecutorService, OxmModelLoader loader) throws Exception {
-
- this.contextId = contextId;
- this.contextIdStr = "[Context-Id=" + contextId + "]";
- this.aaiProvider = aaiDataProvider;
- this.aaiExecutorService = aaiExecutorService;
- this.loader = loader;
-
- 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.aaiConfig = ActiveInventoryConfig.getConfig();
- this.visualizationConfig = VisualizationConfig.getConfig();
- this.shallowEntities = aaiConfig.getAaiRestConfig().getShallowEntities();
-
- this.maxSelfLinkTraversalDepth = visualizationConfig.getMaxSelfLinkTraversalDepth();
-
- this.mapper = new ObjectMapper();
- mapper.setSerializationInclusion(Include.NON_EMPTY);
- mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
- }
-
- public long getContextId() {
- return contextId;
- }
-
- /**
- * A utility method for extracting all entity-type primary key values from a provided self-link
- * and return a set of generic-query API keys.
- *
- * @param parentEntityType
- * @param link
- * @return a list of key values that can be used for this entity with the AAI generic-query API
- */
- protected List<String> extractQueryParamsFromSelfLink(String link) {
-
- List<String> queryParams = new ArrayList<String>();
-
- if (link == null) {
- LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR, "self link is null");
- return queryParams;
- }
-
- Map<String, OxmEntityDescriptor> entityDescriptors = loader.getEntityDescriptors();
-
- try {
-
- URIBuilder urlBuilder = new URIBuilder(link);
- String urlPath = urlBuilder.getPath();
-
- OxmEntityDescriptor descriptor = null;
- String[] urlPathElements = urlPath.split("/");
- List<String> primaryKeyNames = null;
- int index = 0;
- String entityType = null;
-
- while (index < urlPathElements.length) {
-
- descriptor = entityDescriptors.get(urlPathElements[index]);
-
- if (descriptor != null) {
- entityType = urlPathElements[index];
- primaryKeyNames = descriptor.getPrimaryKeyAttributeName();
-
- /*
- * Make sure from what ever index we matched the parent entity-type on that we can extract
- * additional path elements for the primary key values.
- */
-
- if (index + primaryKeyNames.size() < urlPathElements.length) {
-
- for (String primaryKeyName : primaryKeyNames) {
- index++;
- queryParams.add(entityType + "." + primaryKeyName + ":" + urlPathElements[index]);
- }
- } else {
- LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR,
- "Could not extract query parametrs for entity-type = '" + entityType
- + "' from self-link = " + link);
- }
- }
-
- index++;
- }
-
- } catch (URISyntaxException exc) {
-
- LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR,
- "Error extracting query parameters from self-link = " + link + ". Error = "
- + exc.getMessage());
- }
-
- return queryParams;
-
- }
-
- /**
- * Decode complex attribute group.
- *
- * @param ain the ain
- * @param attributeGroup the attribute group
- * @return boolean indicating whether operation was successful (true), / failure(false).
- */
- public boolean decodeComplexAttributeGroup(ActiveInventoryNode ain, JsonNode attributeGroup) {
-
- try {
-
- Iterator<Entry<String, JsonNode>> entityArrays = attributeGroup.fields();
- Entry<String, JsonNode> entityArray = null;
-
- if (entityArrays == null) {
- LOG.error(AaiUiMsgs.ATTRIBUTE_GROUP_FAILURE, attributeGroup.toString());
- ain.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
- return false;
- }
-
- while (entityArrays.hasNext()) {
-
- entityArray = entityArrays.next();
-
- String entityType = entityArray.getKey();
- JsonNode entityArrayObject = entityArray.getValue();
-
- if (entityArrayObject.isArray()) {
-
- Iterator<JsonNode> entityCollection = entityArrayObject.elements();
- JsonNode entity = null;
- while (entityCollection.hasNext()) {
- entity = entityCollection.next();
-
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "decodeComplexAttributeGroup(),"
- + " entity = " + entity.toString());
- }
-
- /**
- * Here's what we are going to do:
- *
- * <li>In the ActiveInventoryNode, on construction maintain a collection of queryParams
- * that is added to for the purpose of discovering parent->child hierarchies.
- *
- * <li>When we hit this block of the code then we'll use the queryParams to feed the
- * generic query to resolve the self-link asynchronously.
- *
- * <li>Upon successful link determination, then and only then will we create a new node
- * in the nodeCache and process the child
- *
- */
-
- ActiveInventoryNode newNode = new ActiveInventoryNode();
- newNode.setEntityType(entityType);
-
- /*
- * This is partially a lie because we actually don't have a self-link for complex nodes
- * discovered in this way.
- */
- newNode.setSelfLinkProcessed(true);
- newNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
- NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
-
- /*
- * copy parent query params into new child
- */
-
- if (SERVICE_INSTANCE.equals(entityType)) {
-
- /*
- * 1707 AAI has an issue being tracked with AAI-8932 where the generic-query cannot be
- * resolved if all the service-instance path keys are provided. The query only works
- * if only the service-instance key and valude are passed due to a historical reason.
- * A fix is being worked on for 1707, and when it becomes available we can revert this
- * small change.
- */
-
- newNode.clearQueryParams();
-
- } else {
-
- /*
- * For all other entity-types we want to copy the parent query parameters into the new node
- * query parameters.
- */
-
- for (String queryParam : ain.getQueryParams()) {
- newNode.addQueryParam(queryParam);
- }
-
- }
-
-
- if (!addComplexGroupToNode(newNode, entity)) {
- LOG.error(AaiUiMsgs.ATTRIBUTE_GROUP_FAILURE, "Failed to add child to parent for child = " + entity.toString());
- }
-
- if (!addNodeQueryParams(newNode)) {
- LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "Error determining node id and key for node = " + newNode.dumpNodeTree(true)
- + " skipping relationship processing");
- newNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.NODE_IDENTITY_ERROR);
- return false;
- } else {
-
- newNode.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
- NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
-
- }
-
-
- /*
- * Order matters for the query params. We need to set the parent ones before the child
- * node
- */
-
- String selfLinkQuery =
- aaiProvider.getGenericQueryForSelfLink(entityType, newNode.getQueryParams());
-
- /**
- * <li>get the self-link
- * <li>add it to the new node
- * <li>generate node id
- * <li>add node to node cache
- * <li>add node id to parent outbound links list
- * <li>process node children (should be automatic) (but don't query and resolve
- * self-link as we already have all the data)
- */
-
- SelfLinkDeterminationTransaction txn = new SelfLinkDeterminationTransaction();
-
- txn.setQueryString(selfLinkQuery);
- txn.setNewNode(newNode);
- txn.setParentNodeId(ain.getNodeId());
- aaiWorkOnHand.incrementAndGet();
- supplyAsync(new PerformSelfLinkDeterminationTask(txn, null, aaiProvider),
- aaiExecutorService).whenComplete((nodeTxn, error) -> {
- aaiWorkOnHand.decrementAndGet();
- if (error != null) {
- LOG.error(AaiUiMsgs.SELF_LINK_DETERMINATION_FAILED_GENERIC, selfLinkQuery);
- } else {
-
- OperationResult opResult = nodeTxn.getOpResult();
-
- ActiveInventoryNode newChildNode = txn.getNewNode();
-
- if (opResult != null && opResult.wasSuccessful()) {
-
- if (opResult.isResolvedLinkFailure()) {
- numFailedLinkResolve.incrementAndGet();
- }
-
- if (opResult.isResolvedLinkFromCache()) {
- numSuccessfulLinkResolveFromCache.incrementAndGet();
- }
-
- if (opResult.isResolvedLinkFromServer()) {
- numSuccessfulLinkResolveFromFromServer.incrementAndGet();
- }
-
- /*
- * extract the self-link from the operational result.
- */
-
- Collection<JsonNode> entityLinks = new ArrayList<JsonNode>();
- JsonNode genericQueryResult = null;
- try {
- genericQueryResult =
- NodeUtils.convertJsonStrToJsonNode(nodeTxn.getOpResult().getResult());
- } catch (Exception exc) {
- LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, JsonNode.class.toString(), exc.getMessage());
- }
-
- NodeUtils.extractObjectsByKey(genericQueryResult, "resource-link",
- entityLinks);
-
- String selfLink = null;
-
- if (entityLinks.size() != 1) {
-
- LOG.error(AaiUiMsgs.SELF_LINK_DETERMINATION_FAILED_UNEXPECTED_LINKS, String.valueOf(entityLinks.size()));
-
- } else {
- selfLink = ((JsonNode) entityLinks.toArray()[0]).asText();
- selfLink = ActiveInventoryConfig.extractResourcePath(selfLink);
-
- newChildNode.setSelfLink(selfLink);
- newChildNode.setNodeId(NodeUtils.generateUniqueShaDigest(selfLink));
-
- String uri = NodeUtils.calculateEditAttributeUri(selfLink);
- if (uri != null) {
- newChildNode.addProperty(TierSupportUiConstants.URI_ATTR_NAME, uri);
- }
-
- ActiveInventoryNode parent = nodeCache.get(txn.getParentNodeId());
-
- if (parent != null) {
- parent.addOutboundNeighbor(newChildNode.getNodeId());
- newChildNode.addInboundNeighbor(parent.getNodeId());
- }
-
- newChildNode.setSelfLinkPendingResolve(false);
- newChildNode.setSelfLinkProcessed(true);
-
- newChildNode.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
- NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
-
- nodeCache.putIfAbsent(newChildNode.getNodeId(), newChildNode);
-
- }
-
- } else {
- LOG.error(AaiUiMsgs.SELF_LINK_RETRIEVAL_FAILED, txn.getQueryString(),
- String.valueOf(nodeTxn.getOpResult().getResultCode()), nodeTxn.getOpResult().getResult());
- newChildNode.setSelflinkRetrievalFailure(true);
- newChildNode.setSelfLinkProcessed(true);
- newChildNode.setSelfLinkPendingResolve(false);
-
- newChildNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.SELF_LINK_DETERMINATION_ERROR);
-
- }
-
- }
-
- });
-
- }
-
- return true;
-
- } else {
- LOG.error(AaiUiMsgs.UNHANDLED_OBJ_TYPE_FOR_ENTITY_TYPE, entityType);
- }
-
- }
- } catch (Exception exc) {
- LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Exception caught while"
- + " decoding complex attribute group - " + exc.getMessage());
- }
-
- return false;
-
- }
-
- /**
- * 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;
- }
-
- JsonNode jsonNode = null;
-
- try {
- jsonNode = mapper.readValue(ain.getOpResult().getResult(), JsonNode.class);
- } catch (Exception exc) {
- 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 (jsonNode == 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;
- }
-
- Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
- Entry<String, JsonNode> field = null;
-
- RelationshipList relationshipList = null;
-
- while (fieldNames.hasNext()) {
-
- field = fieldNames.next();
- String fieldName = field.getKey();
-
- if ("relationship-list".equals(fieldName)) {
-
- try {
- relationshipList = mapper.readValue(field.getValue().toString(), RelationshipList.class);
-
- if (relationshipList != null) {
- ain.addRelationshipList(relationshipList);
- }
-
- } catch (Exception exc) {
- LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to parse relationship-list"
- + " attribute. Parse resulted in error, " + exc.getLocalizedMessage());
- ain.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
- return;
- }
-
- } else {
-
- JsonNode nodeValue = field.getValue();
-
- if (nodeValue != null && nodeValue.isValueNode()) {
-
- if (loader.getEntityDescriptor(fieldName) == null) {
-
- /*
- * entity property name is not an entity, thus we can add this property name and value
- * to our property set
- */
-
- ain.addProperty(fieldName, nodeValue.asText());
-
- }
-
- } else {
-
- if (nodeValue.isArray()) {
-
- if (loader.getEntityDescriptor(fieldName) == null) {
-
- /*
- * entity property name is not an entity, thus we can add this property name and value
- * to our property set
- */
-
- ain.addProperty(field.getKey(), nodeValue.toString());
-
- }
-
- } else {
-
- ain.addComplexGroup(nodeValue);
-
- }
-
- }
- }
-
- }
-
- String uri = NodeUtils.calculateEditAttributeUri(ain.getSelfLink());
- if (uri != null) {
- ain.addProperty(TierSupportUiConstants.URI_ATTR_NAME, uri);
- }
-
- /*
- * We need a special behavior for intermediate entities from the REST model
- *
- * Tenants are not top level entities, and when we want to visualization
- * their children, we need to construct keys that include the parent entity query
- * keys, the current entity type keys, and the child keys. We'll always have the
- * current entity and children, but never the parent entity in the current (1707) REST
- * data model.
- *
- * We have two possible solutions:
- *
- * 1) Try to use the custom-query approach to learn about the entity keys
- * - this could be done, but it could be very expensive for large objects. When we do the first
- * query to get a tenant, it will list all the in and out edges related to this entity,
- * there is presently no way to filter this. But the approach could be made to work and it would be
- * somewhat data-model driven, other than the fact that we have to first realize that the entity
- * that is being searched for is not top-level entity. Once we have globally unique ids for resources
- * this logic will not be needed and everything will be simpler. The only reason we are in this logic
- * at all is to be able to calculate a url for the child entities so we can hash it to generate
- * a globally unique id that can be safely used for the node.
- *
- * *2* Extract the keys from the pathed self-link.
- * This is a bad solution and I don't like it but it will be fast for all resource types, as the
- * information is already encoded in the URI. When we get to a point where we switch to a better
- * globally unique entity identity model, then a lot of the code being used to calculate an entity url
- * to in-turn generate a deterministic globally unique id will disappear.
- *
- *
- * right now we have the following:
- *
- * - cloud-regions/cloud-region/{cloud-region-id}/{cloud-owner-id}/tenants/tenant/{tenant-id}
- *
- */
-
- /*
- * For all entity types use the self-link extraction method to be consistent. Once we have a
- * globally unique identity mechanism for entities, this logic can be revisited.
- */
- ain.clearQueryParams();
- ain.addQueryParams(extractQueryParamsFromSelfLink(ain.getSelfLink()));
-
- ain.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
- 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();
-
- String depthModifier = DEPTH_ALL_MODIFIER;
-
- /*
- * 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.
- */
-
- if (shallowEntities.contains(ain.getEntityType()) && !ain.isRootNode()) {
- depthModifier = NODES_ONLY_MODIFIER;
- }
-
- NodeProcessingTransaction txn = new NodeProcessingTransaction();
- txn.setProcessingNode(ain);
- txn.setRequestParameters(depthModifier);
- aaiWorkOnHand.incrementAndGet();
- supplyAsync(
- new PerformNodeSelfLinkProcessingTask(txn, depthModifier, aaiProvider, aaiConfig),
- aaiExecutorService).whenComplete((nodeTxn, error) -> {
- aaiWorkOnHand.decrementAndGet();
- 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.isResolvedLinkFailure()) {
- numFailedLinkResolve.incrementAndGet();
- }
-
- if (opResult.isResolvedLinkFromCache()) {
- numSuccessfulLinkResolveFromCache.incrementAndGet();
- }
-
- if (opResult.isResolvedLinkFromServer()) {
- 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);
-
- }
- }
-
- });
-
- }
-
- }
-
-
- /**
- * Process neighbors.
- *
- * @param nodeId the node id
- */
- private void processNeighbors(String nodeId) {
-
- if (nodeId == null) {
- LOG.error(AaiUiMsgs.SELF_LINK_PROCESS_NEIGHBORS_ERROR, "Failed to process"
- + " neighbors because nodeId is null.");
- return;
- }
-
- ActiveInventoryNode ain = nodeCache.get(nodeId);
-
- if (ain == null) {
- LOG.error(AaiUiMsgs.SELF_LINK_PROCESS_NEIGHBORS_ERROR, "Failed to process"
- + " neighbors because node could not be found in nodeCache with id, " + nodeId);
- return;
- }
-
- /*
- * process complex attribute and relationships
- */
-
- boolean neighborsProcessedSuccessfully = true;
-
- for (JsonNode n : ain.getComplexGroups()) {
- neighborsProcessedSuccessfully &= decodeComplexAttributeGroup(ain, n);
- }
-
- for (RelationshipList relationshipList : ain.getRelationshipLists()) {
- neighborsProcessedSuccessfully &= addSelfLinkRelationshipChildren(ain, relationshipList);
- }
-
-
- if (neighborsProcessedSuccessfully) {
- ain.changeState(NodeProcessingState.READY, NodeProcessingAction.NEIGHBORS_PROCESSED_OK);
- } else {
- ain.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
- }
-
-
- /*
- * If neighbors fail to process, there is already a call to change the state within the
- * relationship and neighbor processing functions.
- */
-
- }
-
- /**
- * Find and mark root node.
- *
- * @param queryParams the query params
- * @return true, if successful
- */
- private boolean findAndMarkRootNode(QueryParams queryParams) {
-
- 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());
- return true;
- }
- }
-
- return false;
-
- }
-
- /**
- * Process current node states.
- *
- * @param rootNodeDiscovered the root node discovered
- */
- private void processCurrentNodeStates(boolean rootNodeDiscovered) {
- /*
- * Force an evaluation of node depths before determining if we should limit state-based
- * traversal or processing.
- */
- if (rootNodeDiscovered) {
- evaluateNodeDepths();
- }
-
- 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;
- }
-
- case NEIGHBORS_UNPROCESSED: {
-
- /*
- * We use the rootNodeDiscovered flag to ignore depth retrieval thresholds until the root
- * node is identified. Then the evaluative depth calculations should re-balance the graph
- * around the root node.
- */
-
- if (!rootNodeDiscovered || cacheNode.getNodeDepth() < VisualizationConfig.getConfig()
- .getMaxSelfLinkTraversalDepth()) {
-
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
- "SLNC::processCurrentNodeState() -- Node at max depth,"
- + " halting processing at current state = -- "
- + cacheNode.getState() + " nodeId = " + cacheNode.getNodeId());
- }
-
-
-
- processNeighbors(cacheNode.getNodeId());
-
- }
-
- break;
- }
- default:
- break;
-
-
-
- }
-
- }
-
- }
-
- /**
- * Adds the complex group to node.
- *
- * @param targetNode the target node
- * @param attributeGroup the attribute group
- * @return true, if successful
- */
- private boolean addComplexGroupToNode(ActiveInventoryNode targetNode, JsonNode attributeGroup) {
-
- if (attributeGroup == null) {
- targetNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
- return false;
- }
-
- RelationshipList relationshipList = null;
-
- if (attributeGroup.isObject()) {
-
- Iterator<Entry<String, JsonNode>> fields = attributeGroup.fields();
- Entry<String, JsonNode> field = null;
- String fieldName;
- JsonNode fieldValue;
-
- while (fields.hasNext()) {
- field = fields.next();
- fieldName = field.getKey();
- fieldValue = field.getValue();
-
- if (fieldValue.isObject()) {
-
- if (fieldName.equals("relationship-list")) {
-
- try {
- relationshipList =
- mapper.readValue(field.getValue().toString(), RelationshipList.class);
-
- if (relationshipList != null) {
- targetNode.addRelationshipList(relationshipList);
- }
-
- } catch (Exception exc) {
- LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to parse"
- + " relationship-list attribute. Parse resulted in error, "
- + exc.getLocalizedMessage());
- targetNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_ERROR);
- return false;
- }
-
- } else {
- targetNode.addComplexGroup(fieldValue);
- }
-
- } else if (fieldValue.isArray()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
- "Unexpected array type with a key = " + fieldName);
- }
- } else if (fieldValue.isValueNode()) {
- if (loader.getEntityDescriptor(field.getKey()) == null) {
- /*
- * property key is not an entity type, add it to our property set.
- */
- targetNode.addProperty(field.getKey(), fieldValue.asText());
- }
-
- }
- }
-
- } else if (attributeGroup.isArray()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
- "Unexpected array type for attributeGroup = " + attributeGroup);
- }
- } else if (attributeGroup.isValueNode()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
- "Unexpected value type for attributeGroup = " + attributeGroup);
- }
- }
-
- return true;
- }
-
- 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 void setMaxSelfLinkTraversalDepth(int depth) {
- this.maxSelfLinkTraversalDepth = depth;
- }
-
- public int getMaxSelfLinkTraversalDepth() {
- return this.maxSelfLinkTraversalDepth;
- }
-
- public ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache() {
- return nodeCache;
- }
-
- /**
- * Gets the relationship primary key values.
- *
- * @param r the r
- * @param entityType the entity type
- * @param pkeyNames the pkey names
- * @return the relationship primary key values
- */
- private String getRelationshipPrimaryKeyValues(Relationship r, String entityType,
- List<String> pkeyNames) {
-
- StringBuilder sb = new StringBuilder(64);
-
- if (pkeyNames.size() > 0) {
- String primaryKey = extractKeyValueFromRelationData(r, entityType + "." + 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, " + entityType + "." + pkeyNames.get(0)
- + ", from relationship data, " + r.toString());
- return null;
- }
-
- for (int i = 1; i < pkeyNames.size(); i++) {
-
- String kv = extractKeyValueFromRelationData(r, entityType + "." + 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, "
- + entityType + "." + pkeyNames.get(i)
- + ", from relationship data, " + r.toString());
- return null;
- }
- }
-
- return sb.toString();
-
- }
-
- return null;
-
- }
-
- /**
- * Extract key value from relation data.
- *
- * @param r the r
- * @param keyName the key name
- * @return the string
- */
- private String extractKeyValueFromRelationData(Relationship r, String keyName) {
-
- RelationshipData[] rdList = r.getRelationshipData();
-
- for (RelationshipData relData : rdList) {
-
- if (relData.getRelationshipKey().equals(keyName)) {
- return relData.getRelationshipValue();
- }
- }
-
- return null;
- }
-
- /**
- * Determine node id and key.
- *
- * @param ain the ain
- * @return true, if successful
- */
- private boolean addNodeQueryParams(ActiveInventoryNode ain) {
-
- if (ain == null) {
- LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "ActiveInventoryNode is null");
- return false;
- }
-
- List<String> pkeyNames =
- loader.getEntityDescriptor(ain.getEntityType()).getPrimaryKeyAttributeName();
-
- if (pkeyNames == null || pkeyNames.size() == 0) {
- LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "Primary key names is empty");
- return false;
- }
-
- StringBuilder sb = new StringBuilder(64);
-
- if (pkeyNames.size() > 0) {
- String primaryKey = ain.getProperties().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 entity properties");
- return false;
- }
-
- for (int i = 1; i < pkeyNames.size(); i++) {
-
- String kv = ain.getProperties().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 entity properties");
- return false;
- }
- }
-
- /*final String nodeId = NodeUtils.generateUniqueShaDigest(ain.getEntityType(),
- NodeUtils.concatArray(pkeyNames, "/"), sb.toString());*/
-
- //ain.setNodeId(nodeId);
- ain.setPrimaryKeyName(NodeUtils.concatArray(pkeyNames, "/"));
- ain.setPrimaryKeyValue(sb.toString());
-
- if (ain.getEntityType() != null && ain.getPrimaryKeyName() != null
- && ain.getPrimaryKeyValue() != null) {
- ain.addQueryParam(
- ain.getEntityType() + "." + ain.getPrimaryKeyName() + ":" + ain.getPrimaryKeyValue());
- }
- return true;
-
- }
-
- return false;
-
- }
-
- /**
- * Adds the self link relationship children.
- *
- * @param processingNode the processing node
- * @param relationshipList the relationship list
- * @return true, if successful
- */
- private boolean addSelfLinkRelationshipChildren(ActiveInventoryNode processingNode,
- RelationshipList relationshipList) {
-
- if (relationshipList == null) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "No relationships added to parent node = "
- + processingNode.getNodeId() + " because relationshipList is empty");
- processingNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
- return false;
- }
-
- OxmModelLoader modelLoader = OxmModelLoader.getInstance();
-
- Relationship[] relationshipArray = relationshipList.getRelationshipList();
- OxmEntityDescriptor descriptor = null;
-
- if (relationshipArray != null) {
-
- ActiveInventoryNode newNode = null;
- String resourcePath = null;
-
- for (Relationship r : relationshipArray) {
-
- resourcePath = ActiveInventoryConfig.extractResourcePath(r.getRelatedLink());
-
- String nodeId = NodeUtils.generateUniqueShaDigest(resourcePath);
-
- if (nodeId == null) {
-
- LOG.error(AaiUiMsgs.SKIPPING_RELATIONSHIP, r.toString());
- processingNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.NODE_IDENTITY_ERROR);
- return false;
- }
-
- newNode = new ActiveInventoryNode();
-
- String entityType = r.getRelatedTo();
-
- if (r.getRelationshipData() != null) {
- for (RelationshipData rd : r.getRelationshipData()) {
- newNode.addQueryParam(rd.getRelationshipKey() + ":" + rd.getRelationshipValue());
- }
- }
-
- descriptor = modelLoader.getEntityDescriptor(r.getRelatedTo());
-
- newNode.setNodeId(nodeId);
- newNode.setEntityType(entityType);
- newNode.setSelfLink(resourcePath);
-
- processingNode.addOutboundNeighbor(nodeId);
-
- if (descriptor != null) {
-
- List<String> pkeyNames = descriptor.getPrimaryKeyAttributeName();
-
- newNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
- NodeProcessingAction.SELF_LINK_SET);
-
- newNode.setPrimaryKeyName(NodeUtils.concatArray(pkeyNames, "/"));
-
- String primaryKeyValues = getRelationshipPrimaryKeyValues(r, entityType, pkeyNames);
- newNode.setPrimaryKeyValue(primaryKeyValues);
-
- } else {
-
- LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR,
- "Failed to parse entity because OXM descriptor could not be found for type = "
- + r.getRelatedTo());
-
- newNode.changeState(NodeProcessingState.ERROR,
- NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
-
- }
-
- if (nodeCache.putIfAbsent(nodeId, newNode) != null) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
- "Failed to add node to nodeCache because it already exists. Node id = "
- + newNode.getNodeId());
- }
- }
-
- }
-
- }
-
- return true;
-
- }
-
- /**
- * 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();
-
- newNode.setNodeId(searchTargetEntity.getId());
- newNode.setEntityType(searchTargetEntity.getEntityType());
- newNode.setPrimaryKeyName(getEntityTypePrimaryKeyName(searchTargetEntity.getEntityType()));
- newNode.setPrimaryKeyValue(searchTargetEntity.getEntityPrimaryKeyValue());
-
- if (newNode.getEntityType() != null && newNode.getPrimaryKeyName() != null
- && newNode.getPrimaryKeyValue() != null) {
- newNode.addQueryParam(
- newNode.getEntityType() + "." + newNode.getPrimaryKeyName() + ":" + newNode.getPrimaryKeyValue());
- }
- /*
- * This code may need some explanation. In any graph there will be a single root node. The root
- * node is really the center of the universe, and for now, we are tagging the search target as
- * the root node. Everything else in the visualization of the graph will be centered around this
- * node as the focal point of interest.
- *
- * Due to it's special nature, there will only ever be one root node, and it's node depth will
- * always be equal to zero.
- */
-
- if (queryParams.getSearchTargetNodeId().equals(newNode.getNodeId())) {
- newNode.setNodeDepth(0);
- newNode.setRootNode(true);
- LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
- }
-
- newNode.setSelfLink(searchTargetEntity.getLink());
-
- nodeCache.putIfAbsent(newNode.getNodeId(), newNode);
- }
-
- /**
- * Checks for out standing work.
- *
- * @return true, if successful
- */
- private boolean hasOutStandingWork() {
-
- int numNodesWithPendingStates = 0;
-
- /*
- * Force an evaluation of node depths before determining if we should limit state-based
- * traversal or processing.
- */
-
- evaluateNodeDepths();
-
- for (ActiveInventoryNode n : nodeCache.values()) {
-
- switch (n.getState()) {
-
- case READY:
- case ERROR: {
- // do nothing, these are our normal
- // exit states
- break;
- }
-
- case NEIGHBORS_UNPROCESSED: {
-
- if (n.getNodeDepth() < VisualizationConfig.getConfig().getMaxSelfLinkTraversalDepth()) {
- /*
- * Only process our neighbors relationships if our current depth is less than the max
- * depth
- */
- numNodesWithPendingStates++;
- }
-
- break;
- }
-
- default: {
-
- /*
- * for all other states, there is work to be done
- */
- numNodesWithPendingStates++;
- }
-
- }
-
- }
-
- LOG.debug(AaiUiMsgs.OUTSTANDING_WORK_PENDING_NODES, String.valueOf(numNodesWithPendingStates));
-
- return (numNodesWithPendingStates > 0);
-
- }
+public interface VisualizationContext {
/**
* Process self links.
* @param skeletonNode the skeleton node
* @param queryParams the query params
*/
- 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;
- }
-
- processSearchableEntity(searchtargetEntity, queryParams);
-
- long startTimeInMs = System.currentTimeMillis();
-
- /*
- * wait until all transactions are complete or guard-timer expires.
- */
-
- long totalResolveTime = 0;
- boolean hasOutstandingWork = hasOutStandingWork();
- boolean outstandingWorkGuardTimerFired = false;
- long maxGuardTimeInMs = 5000;
- long guardTimeInMs = 0;
- boolean foundRootNode = false;
-
-
- /*
- * TODO: Put a count-down-latch in place of the while loop, but if we do that then
- * we'll need to decouple the visualization processing from the main thread so it can continue to process while
- * the main thread is waiting on for count-down-latch gate to open. This may also be easier once we move to the
- * VisualizationService + VisualizationContext ideas.
- */
-
-
- while (hasOutstandingWork || !outstandingWorkGuardTimerFired) {
-
- if (!foundRootNode) {
- foundRootNode = findAndMarkRootNode(queryParams);
- }
-
- processCurrentNodeStates(foundRootNode);
-
- verifyOutboundNeighbors();
-
- try {
- Thread.sleep(500);
- } catch (InterruptedException exc) {
- LOG.error(AaiUiMsgs.PROCESSING_LOOP_INTERUPTED, exc.getMessage());
- return;
- }
-
- totalResolveTime = (System.currentTimeMillis() - startTimeInMs);
-
- if (!hasOutstandingWork) {
-
- guardTimeInMs += 500;
-
- if (guardTimeInMs > maxGuardTimeInMs) {
- outstandingWorkGuardTimerFired = true;
- }
- } else {
- guardTimeInMs = 0;
- }
-
- hasOutstandingWork = hasOutStandingWork();
-
- }
-
- 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 (VisualizationConfig.getConfig().makeAllNeighborsBidirectional()) {
- targetNode.addOutboundNeighbor(srcNode.getNodeId());
- }
-
- }
-
- }
-
- }
-
- }
-
- /**
- * Evaluate node depths.
- */
- private void evaluateNodeDepths() {
+ void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams);
- int numChanged = -1;
- int numAttempts = 0;
+ ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache();
- 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");
- }
- }
-
- }
+ InlineMessage getInlineMessage();
-
- /**
- * 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 = loader.getEntityDescriptor(entityType);
-
- if (descriptor == null) {
- LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE, "oxm entity"
- + " descriptor for entityType = " + entityType);
- return null;
- }
-
- List<String> pkeyNames = descriptor.getPrimaryKeyAttributeName();
-
- if (pkeyNames == null || pkeyNames.size() == 0) {
- LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE, "node primary"
- + " key because descriptor primary key names is empty");
- return null;
- }
+ int getNumFailedLinkResolve();
- return NodeUtils.concatArray(pkeyNames, "/");
+ int getNumSuccessfulLinkResolveFromCache();
- }
+ int getNumSuccessfulLinkResolveFromFromServer();
}