2 * ============LICENSE_START===================================================
3 * SPARKY (AAI UI service)
4 * ============================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
8 * ============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=====================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.onap.aai.sparky.viewandinspect.services;
27 import static java.util.concurrent.CompletableFuture.supplyAsync;
29 import java.io.IOException;
30 import java.util.List;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ExecutorService;
34 import java.util.concurrent.atomic.AtomicInteger;
36 import org.onap.aai.cl.api.Logger;
37 import org.onap.aai.cl.eelf.LoggerFactory;
38 import org.onap.aai.restclient.client.OperationResult;
39 import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
40 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
41 import org.onap.aai.sparky.dal.GizmoAdapter;
42 import org.onap.aai.sparky.logging.AaiUiMsgs;
43 import org.onap.aai.sparky.sync.entity.SearchableEntity;
44 import org.onap.aai.sparky.util.NodeUtils;
45 import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
46 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
47 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
48 import org.onap.aai.sparky.viewandinspect.entity.GizmoEntity;
49 import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipEntity;
50 import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipHint;
51 import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
52 import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
53 import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
54 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
55 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
56 import org.onap.aai.sparky.viewandinspect.task.PerformGizmoNodeSelfLinkProcessingTask;
58 import com.fasterxml.jackson.annotation.JsonInclude.Include;
59 import com.fasterxml.jackson.databind.ObjectMapper;
60 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
63 * The Class SelfLinkNodeCollector.
65 public class BaseGizmoVisualizationContext implements VisualizationContext {
67 private static final int MAX_DEPTH_EVALUATION_ATTEMPTS = 100;
69 private static final Logger LOG =
70 LoggerFactory.getInstance().getLogger(BaseGizmoVisualizationContext.class);
72 private final GizmoAdapter gizmoAdapter;
74 private AtomicInteger numLinksDiscovered;
75 private AtomicInteger numSuccessfulLinkResolveFromCache;
76 private AtomicInteger numSuccessfulLinkResolveFromFromServer;
77 private AtomicInteger numFailedLinkResolve;
78 private AtomicInteger aaiWorkOnHand;
80 private VisualizationConfigs visualizationConfigs;
82 private AtomicInteger totalLinksRetrieved;
84 private final long contextId;
85 private final String contextIdStr;
86 private long lastProcessStatesSummaryLogInMs = -1;
89 private ObjectMapper mapper;
90 private InlineMessage inlineMessage = null;
92 private ExecutorService graphExecutorService;
93 private OxmEntityLookup oxmEntityLookup;
94 private boolean rootNodeFound;
97 * The node cache is intended to be a flat structure indexed by a primary key to avoid needlessly
98 * re-requesting the same self-links over-and-over again, to speed up the overall render time and
99 * more importantly to reduce the network cost of determining information we already have.
101 private ConcurrentHashMap<String, ActiveInventoryNode> nodeCache;
104 * Instantiates a new self link node collector.
106 * @param loader the loader
107 * @throws Exception the exception
109 public BaseGizmoVisualizationContext(long contextId, GizmoAdapter gizmoAdapter,
110 ExecutorService graphExecutorService, VisualizationConfigs visualizationConfigs,
111 OxmEntityLookup oxmEntityLookup) throws Exception {
113 this.contextId = contextId;
114 this.contextIdStr = "[Context-Id=" + contextId + "]";
115 this.gizmoAdapter = gizmoAdapter;
116 this.graphExecutorService = graphExecutorService;
117 this.visualizationConfigs = visualizationConfigs;
118 this.oxmEntityLookup = oxmEntityLookup;
120 this.nodeCache = new ConcurrentHashMap<String, ActiveInventoryNode>();
121 this.numLinksDiscovered = new AtomicInteger(0);
122 this.totalLinksRetrieved = new AtomicInteger(0);
123 this.numSuccessfulLinkResolveFromCache = new AtomicInteger(0);
124 this.numSuccessfulLinkResolveFromFromServer = new AtomicInteger(0);
125 this.numFailedLinkResolve = new AtomicInteger(0);
126 this.aaiWorkOnHand = new AtomicInteger(0);
128 this.mapper = new ObjectMapper();
129 mapper.setSerializationInclusion(Include.NON_EMPTY);
130 mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
131 this.rootNodeFound = false;
134 protected boolean isRootNodeFound() {
135 return rootNodeFound;
138 protected void setRootNodeFound(boolean rootNodeFound) {
139 this.rootNodeFound = rootNodeFound;
142 public long getContextId() {
146 public GizmoAdapter getGizmoAdapter() {
151 * Process self link response.
153 * @param nodeId the node id
155 private void processSelfLinkResponse(String nodeId) {
157 if (nodeId == null) {
158 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
159 "Cannot process self link" + " response because nodeId is null");
163 ActiveInventoryNode ain = nodeCache.get(nodeId);
166 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
167 "Cannot process self link response" + " because can't find node for id = " + nodeId);
171 GizmoEntity gizmoEntity = null;
174 gizmoEntity = mapper.readValue(ain.getOpResult().getResult(), GizmoEntity.class);
175 } catch (Exception exc) {
176 exc.printStackTrace();
177 LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to marshal json"
178 + " response str into JsonNode with error, " + exc.getLocalizedMessage());
179 ain.changeState(NodeProcessingState.ERROR,
180 NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
184 if (gizmoEntity == null) {
186 LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR,
187 "Failed to parse json node str." + " Parse resulted a null value.");
188 ain.changeState(NodeProcessingState.ERROR,
189 NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
194 * Now that we have the gizmo entity we can populate the AIN node with it, as well as the
198 ain.setEntityType(gizmoEntity.getType());
200 ain.setPrimaryKeyName(getEntityTypePrimaryKeyName(gizmoEntity.getType()));
202 OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(gizmoEntity);
204 if (descriptor != null) {
205 ain.setPrimaryKeyValue(getPrimaryKeyValues(gizmoEntity.getProperties(),
206 descriptor.getPrimaryKeyAttributeNames()));
208 LOG.error(AaiUiMsgs.ERROR_GENERIC, "Could not determine oxm descriptor for entity type = " + gizmoEntity.getType());
211 gizmoEntity.getProperties().forEach((key, value) -> {
212 ain.getProperties().put(key, value);
215 // add edit attributes link
216 if (ain.getSelfLink() != null) {
217 ain.addProperty(SparkyConstants.URI_ATTR_NAME, ain.getSelfLink());
223 * Only discover neighbors if our depth is less than the Max-Traversal-Depth
226 if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
229 * I think the next thing to do is:
231 * 1. Calculate the source / target node id 2. Add the nodeId to the incoming / outgoing links
232 * collection 3. Add the node to the node cache for processing
235 String resourceLink = null;
236 String relationshipNodeId = null;
237 ActiveInventoryNode relationshipNode = null;
239 for (GizmoRelationshipHint inRelationship : gizmoEntity.getIn()) {
241 if (inRelationship.getSource() != null) {
243 resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(inRelationship.getSource());
244 relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
246 if (!nodeCache.containsKey(relationshipNodeId)) {
248 relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
249 relationshipNode.setNodeId(relationshipNodeId);
250 relationshipNode.setSelfLink(resourceLink);
251 relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
252 NodeProcessingAction.NEW_NODE_PROCESSED);
254 ain.addInboundNeighbor(relationshipNodeId);
256 addNode(relationshipNode);
263 for (GizmoRelationshipHint outRelationship : gizmoEntity.getOut()) {
265 if (outRelationship.getTarget() != null) {
267 resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(outRelationship.getTarget());
268 relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
270 if (!nodeCache.containsKey(relationshipNodeId)) {
272 relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
273 relationshipNode.setNodeId(relationshipNodeId);
274 relationshipNode.setSelfLink(resourceLink);
275 relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
276 NodeProcessingAction.NEW_NODE_PROCESSED);
278 ain.addOutboundNeighbor(relationshipNodeId);
280 addNode(relationshipNode);
288 ain.changeState(NodeProcessingState.READY, NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
293 * Perform self link resolve.
295 * @param nodeId the node id
297 private void performSelfLinkResolve(String nodeId) {
299 if (nodeId == null) {
300 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
301 "Resolve of self-link" + " has been skipped because provided nodeId is null");
305 ActiveInventoryNode ain = nodeCache.get(nodeId);
308 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Failed to find node with id, " + nodeId
309 + ", from node cache. Resolve self-link method has been skipped.");
313 if (!ain.isSelfLinkPendingResolve()) {
315 ain.setSelfLinkPendingResolve(true);
317 // kick off async self-link resolution
319 if (LOG.isDebugEnabled()) {
320 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
321 "About to process node in SELF_LINK_UNPROCESSED State, link = " + ain.getSelfLink());
324 numLinksDiscovered.incrementAndGet();
327 * If the current node is the search target, we want to see everything the node has to offer
328 * from the self-link and not filter it to a single node.
331 NodeProcessingTransaction txn = new NodeProcessingTransaction();
332 txn.setProcessingNode(ain);
333 txn.setRequestParameters(null);
334 aaiWorkOnHand.incrementAndGet();
335 supplyAsync(new PerformGizmoNodeSelfLinkProcessingTask(txn, null, gizmoAdapter),
336 graphExecutorService).whenComplete((nodeTxn, error) -> {
341 * an error processing the self link should probably result in the node processing
342 * state shifting to ERROR
345 nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
347 nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
348 NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
350 nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
354 totalLinksRetrieved.incrementAndGet();
356 OperationResult opResult = nodeTxn.getOpResult();
358 if (opResult != null && opResult.wasSuccessful()) {
360 if (!opResult.wasSuccessful()) {
361 numFailedLinkResolve.incrementAndGet();
364 if (opResult.isFromCache()) {
365 numSuccessfulLinkResolveFromCache.incrementAndGet();
367 numSuccessfulLinkResolveFromFromServer.incrementAndGet();
371 nodeTxn.getProcessingNode().setOpResult(opResult);
372 nodeTxn.getProcessingNode().changeState(
373 NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
374 NodeProcessingAction.SELF_LINK_RESOLVE_OK);
376 nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
377 nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
380 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
381 "Self Link retrieval for link," + txn.getSelfLinkWithModifiers()
382 + ", failed with error code," + nodeTxn.getOpResult().getResultCode()
383 + ", and message," + nodeTxn.getOpResult().getResult());
385 nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
386 nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
388 nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
389 NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
391 nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
396 aaiWorkOnHand.decrementAndGet();
404 public GizmoRelationshipEntity getGizmoRelationshipEntity(String gizmoJsonResponse) {
406 GizmoRelationshipEntity gizmoRelationship = null;
408 gizmoRelationship = mapper.readValue(gizmoJsonResponse, GizmoRelationshipEntity.class);
409 } catch (IOException exc) {
410 LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to map json to GizmoRelationshipEntity. Error: " + exc.getMessage());
413 return gizmoRelationship;
417 public String getPrimaryKeyValues(Map<String, String> properties, List<String> pkeyNames) {
419 StringBuilder sb = new StringBuilder(64);
421 if (pkeyNames.size() > 0) {
422 String primaryKey = properties.get(pkeyNames.get(0));
423 if (primaryKey != null) {
424 sb.append(primaryKey);
426 // this should be a fatal error because unless we can
427 // successfully retrieve all the expected keys we'll end up
428 // with a garbage node
429 LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract" + " keyName, "
430 + pkeyNames.get(0) + ", from properties , " + properties);
434 for (int i = 1; i < pkeyNames.size(); i++) {
436 String kv = properties.get(pkeyNames.get(i));
438 sb.append("/").append(kv);
440 // this should be a fatal error because unless we can
441 // successfully retrieve all the expected keys we'll end up
442 // with a garbage node
443 LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: failed to extract keyName, "
444 + pkeyNames.get(i) + ", from properties, " + properties);
449 return sb.toString();
460 * Find and mark root node.
462 * @param queryParams the query params
463 * @return true, if successful
465 private void findAndMarkRootNode(QueryParams queryParams) {
467 if (isRootNodeFound()) {
471 for (ActiveInventoryNode cacheNode : nodeCache.values()) {
473 if (queryParams.getSearchTargetNodeId().equals(cacheNode.getNodeId())) {
474 cacheNode.setNodeDepth(0);
475 cacheNode.setRootNode(true);
476 LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
477 setRootNodeFound(true);
483 public void addNode(ActiveInventoryNode node) {
489 nodeCache.putIfAbsent(node.getNodeId(), node);
492 public VisualizationConfigs getVisualizationConfigs() {
493 return visualizationConfigs;
496 public void setVisualizationConfigs(VisualizationConfigs visualizationConfigs) {
497 this.visualizationConfigs = visualizationConfigs;
500 public OxmEntityLookup getOxmEntityLookup() {
501 return oxmEntityLookup;
504 public void setOxmEntityLookup(OxmEntityLookup oxmEntityLookup) {
505 this.oxmEntityLookup = oxmEntityLookup;
508 public ObjectMapper getMapper() {
512 public void setMapper(ObjectMapper mapper) {
513 this.mapper = mapper;
516 private void dumpThrottledWorkOnHandLog() {
517 dumpThrottledWorkOnHandLog(false);
520 private void dumpThrottledWorkOnHandLog(boolean override) {
522 if ((lastProcessStatesSummaryLogInMs < 0)
523 || ((System.currentTimeMillis() > (lastProcessStatesSummaryLogInMs + 5000))) || override) {
525 lastProcessStatesSummaryLogInMs = System.currentTimeMillis();
530 int numSelfLinkUnresolved = 0;
531 int numSelfLinkResponseUnprocessed = 0;
533 for (ActiveInventoryNode cacheNode : nodeCache.values()) {
535 switch (cacheNode.getState()) {
551 case SELF_LINK_UNRESOLVED: {
552 numSelfLinkUnresolved++;
556 case SELF_LINK_RESPONSE_UNPROCESSED: {
557 numSelfLinkResponseUnprocessed++;
567 LOG.info(AaiUiMsgs.INFO_GENERIC,
569 "ProcessCurrentStates for ContextId=%s, [PendingTxns=%d, numInit=%d, numSelfLinkUnresolved=%d, numSelfLinkResponseUnProcessed=%d, numReady=%d, numError=%d]",
570 contextIdStr, aaiWorkOnHand.get(), numInit, numSelfLinkUnresolved, numSelfLinkResponseUnprocessed,
571 numReady, numError));
577 * Process current node states.
579 * @param rootNodeDiscovered the root node discovered
581 private void processCurrentNodeStates(QueryParams queryParams) {
583 * Force an evaluation of node depths before determining if we should limit state-based
584 * traversal or processing.
587 findAndMarkRootNode(queryParams);
589 verifyOutboundNeighbors();
591 for (ActiveInventoryNode cacheNode : nodeCache.values()) {
593 if (LOG.isDebugEnabled()) {
594 LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "processCurrentNodeState(), nid = "
595 + cacheNode.getNodeId() + " , nodeDepth = " + cacheNode.getNodeDepth());
598 switch (cacheNode.getState()) {
601 processInitialState(cacheNode.getNodeId());
610 case SELF_LINK_UNRESOLVED: {
611 performSelfLinkResolve(cacheNode.getNodeId());
615 case SELF_LINK_RESPONSE_UNPROCESSED: {
616 processSelfLinkResponse(cacheNode.getNodeId());
626 dumpThrottledWorkOnHandLog();
632 public int getNumSuccessfulLinkResolveFromCache() {
633 return numSuccessfulLinkResolveFromCache.get();
636 public int getNumSuccessfulLinkResolveFromFromServer() {
637 return numSuccessfulLinkResolveFromFromServer.get();
640 public int getNumFailedLinkResolve() {
641 return numFailedLinkResolve.get();
644 public InlineMessage getInlineMessage() {
645 return inlineMessage;
648 public void setInlineMessage(InlineMessage inlineMessage) {
649 this.inlineMessage = inlineMessage;
652 public ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache() {
659 * Process initial state.
661 * @param nodeId the node id
663 private void processInitialState(String nodeId) {
665 if (nodeId == null) {
666 LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE, "Node id is null");
670 ActiveInventoryNode cachedNode = nodeCache.get(nodeId);
672 if (cachedNode == null) {
673 LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE,
674 "Node cannot be" + " found for nodeId, " + nodeId);
678 if (cachedNode.getSelfLink() == null) {
680 if (cachedNode.getNodeId() == null) {
683 * if the self link is null at the INIT state, which could be valid if this node is a
684 * complex attribute group which didn't originate from a self-link, but in that situation
685 * both the node id and node key should already be set.
688 cachedNode.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NODE_IDENTITY_ERROR);
692 if (cachedNode.getNodeId() != null) {
695 * This should be the success path branch if the self-link is not set
698 cachedNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
699 NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
705 if (cachedNode.hasResolvedSelfLink()) {
706 LOG.error(AaiUiMsgs.INVALID_RESOLVE_STATE_DURING_INIT);
707 cachedNode.changeState(NodeProcessingState.ERROR,
708 NodeProcessingAction.UNEXPECTED_STATE_TRANSITION);
710 cachedNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
711 NodeProcessingAction.SELF_LINK_SET);
717 * Process skeleton node.
719 * @param skeletonNode the skeleton node
720 * @param queryParams the query params
722 private void processSearchableEntity(SearchableEntity searchTargetEntity,
723 QueryParams queryParams) {
725 if (searchTargetEntity == null) {
729 if (searchTargetEntity.getId() == null) {
730 LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_SKELETON_NODE, "Failed to process skeleton"
731 + " node because nodeId is null for node, " + searchTargetEntity.getLink());
735 ActiveInventoryNode newNode =
736 new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
738 newNode.setNodeId(searchTargetEntity.getId());
740 newNode.setNodeDepth(0);
741 newNode.setRootNode(true);
742 LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
743 setRootNodeFound(true);
745 newNode.setSelfLink(searchTargetEntity.getLink());
747 nodeCache.putIfAbsent(newNode.getNodeId(), newNode);
750 private int getTotalWorkOnHand() {
752 int numNodesWithPendingStates = 0;
754 if (isRootNodeFound()) {
755 evaluateNodeDepths();
758 for (ActiveInventoryNode n : nodeCache.values()) {
760 switch (n.getState()) {
764 // do nothing, these are our normal
772 * for all other states, there is work to be done
774 numNodesWithPendingStates++;
781 return (aaiWorkOnHand.get() + numNodesWithPendingStates);
786 * Checks for out standing work.
788 * @return true, if successful
790 private void processOutstandingWork(QueryParams queryParams) {
792 while (getTotalWorkOnHand() > 0) {
795 * Force an evaluation of node depths before determining if we should limit state-based
796 * traversal or processing.
799 processCurrentNodeStates(queryParams);
803 } catch (InterruptedException exc) {
804 LOG.error(AaiUiMsgs.PROCESSING_LOOP_INTERUPTED, exc.getMessage());
810 dumpThrottledWorkOnHandLog(true);
818 * org.onap.aai.sparky.viewandinspect.services.VisualizationContext#processSelfLinks(org.onap.aai.
819 * sparky.sync.entity.SearchableEntity, org.onap.aai.sparky.viewandinspect.entity.QueryParams)
822 public void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams) {
827 if (searchtargetEntity == null) {
828 LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
829 contextIdStr + " - Failed to" + " processSelfLinks, searchtargetEntity is null");
833 long startTimeInMs = System.currentTimeMillis();
835 processSearchableEntity(searchtargetEntity, queryParams);
838 * This method is blocking until we decouple it with a CountDownLatch await condition, and
839 * make the internal graph processing more event-y.
842 processOutstandingWork(queryParams);
844 long totalResolveTime = (System.currentTimeMillis() - startTimeInMs);
846 long opTime = System.currentTimeMillis() - startTimeInMs;
848 LOG.info(AaiUiMsgs.ALL_TRANSACTIONS_RESOLVED, String.valueOf(totalResolveTime),
849 String.valueOf(totalLinksRetrieved.get()), String.valueOf(opTime));
851 } catch (Exception exc) {
852 LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR, exc.getMessage());
858 * Verify outbound neighbors.
860 private void verifyOutboundNeighbors() {
862 for (ActiveInventoryNode srcNode : nodeCache.values()) {
864 for (String targetNodeId : srcNode.getOutboundNeighbors()) {
866 ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
868 if (targetNode != null && srcNode.getNodeId() != null) {
870 targetNode.addInboundNeighbor(srcNode.getNodeId());
872 if (this.visualizationConfigs.makeAllNeighborsBidirectional()) {
873 targetNode.addOutboundNeighbor(srcNode.getNodeId());
885 * Evaluate node depths.
887 private void evaluateNodeDepths() {
892 while (numChanged != 0) {
897 for (ActiveInventoryNode srcNode : nodeCache.values()) {
899 if (srcNode.getState() == NodeProcessingState.INIT) {
902 * this maybe the only state that we don't want to to process the node depth on, because
903 * typically it won't have any valid fields set, and it may remain in a partial state
904 * until we have processed the self-link.
911 for (String targetNodeId : srcNode.getOutboundNeighbors()) {
912 ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
914 if (targetNode != null) {
916 if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
922 for (String targetNodeId : srcNode.getInboundNeighbors()) {
923 ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
925 if (targetNode != null) {
927 if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
934 if (numAttempts >= MAX_DEPTH_EVALUATION_ATTEMPTS) {
935 LOG.info(AaiUiMsgs.MAX_EVALUATION_ATTEMPTS_EXCEEDED);
941 if (LOG.isDebugEnabled()) {
942 if (numAttempts > 0) {
943 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
944 "Evaluate node depths completed in " + numAttempts + " attempts");
946 LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
947 "Evaluate node depths completed in 0 attempts because all nodes at correct depth");
955 * Gets the entity type primary key name.
957 * @param entityType the entity type
958 * @return the entity type primary key name
962 private String getEntityTypePrimaryKeyName(String entityType) {
964 if (entityType == null) {
965 LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
966 "node primary key" + " name because entity type is null");
970 OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
972 if (descriptor == null) {
973 LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
974 "oxm entity" + " descriptor for entityType = " + entityType);
978 List<String> pkeyNames = descriptor.getPrimaryKeyAttributeNames();
980 if (pkeyNames == null || pkeyNames.size() == 0) {
981 LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
982 "node primary" + " key because descriptor primary key names is empty");
986 return NodeUtils.concatArray(pkeyNames, "/");