2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 package org.onap.aai.sparky.viewandinspect.entity;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
30 import java.util.Map.Entry;
32 import java.util.concurrent.ConcurrentLinkedDeque;
33 import java.util.concurrent.atomic.AtomicBoolean;
35 import org.onap.aai.cl.api.Logger;
36 import org.onap.aai.cl.eelf.LoggerFactory;
37 import org.onap.aai.restclient.client.OperationResult;
38 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
39 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
40 import org.onap.aai.sparky.logging.AaiUiMsgs;
41 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
42 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
43 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
45 import com.fasterxml.jackson.databind.JsonNode;
46 import com.fasterxml.jackson.databind.ObjectMapper;
49 * The Class ActiveInventoryNode.
51 public class ActiveInventoryNode {
53 private static final Logger LOG = LoggerFactory.getInstance().getLogger(
54 ActiveInventoryNode.class);
56 public static final int DEFAULT_INIT_NODE_DEPTH = 1000;
58 private String nodeId;
59 private String selfLink;
61 private boolean isRootNode;
62 private ConcurrentLinkedDeque<String> inboundNeighbors;
63 private ConcurrentLinkedDeque<String> outboundNeighbors;
65 private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
66 private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
68 private List<JsonNode> complexGroups;
69 private List<RelationshipList> relationshipLists;
70 private int nodeDepth;
71 private OperationResult opResult;
73 private boolean processingErrorOccurred;
74 private List<String> errorCauses;
75 private boolean selflinkRetrievalFailure;
76 private NodeProcessingState state;
78 private boolean processedNeighbors;
80 private boolean selfLinkPendingResolve;
83 * I think we shouldn't be using this crutch flags. If these things are meant
84 * to represent the current state of the node, then they should be legitimate
88 private boolean selfLinkDeterminationPending;
90 private AtomicBoolean selfLinkProcessed;
91 private AtomicBoolean nodeIntegrityProcessed;
93 private OxmModelLoader oxmModelLoader;
94 private VisualizationConfigs visualizationConfigs;
96 private String entityType;
97 private String primaryKeyName;
98 private String primaryKeyValue;
100 private boolean nodeValidated;
101 private boolean nodeIssue;
102 private boolean ignoredByFilter;
104 private boolean resolvedSelfLink;
106 private Map<String, String> properties;
107 private ArrayList<String> queryParams;
109 private ObjectMapper mapper;
111 private OxmEntityLookup oxmEntityLookup;
114 * Instantiates a new active inventory node.
118 public ActiveInventoryNode(VisualizationConfigs visualizationConfigs, OxmEntityLookup oxmEntityLookup) {
119 this.oxmEntityLookup = oxmEntityLookup;
121 this.entityType = null;
122 this.selfLink = null;
123 this.properties = new HashMap<String, String>();
124 this.processingErrorOccurred = false;
125 this.errorCauses = new ArrayList<String>();
126 this.selflinkRetrievalFailure = false;
127 this.nodeIssue = false;
128 this.nodeValidated = false;
129 this.state = NodeProcessingState.INIT;
130 this.selfLinkPendingResolve = false;
131 this.selfLinkDeterminationPending = false;
133 selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
134 nodeIntegrityProcessed = new AtomicBoolean(Boolean.FALSE);
135 oxmModelLoader = null;
136 this.visualizationConfigs = visualizationConfigs ;
139 inboundNeighbors = new ConcurrentLinkedDeque<String>();
140 outboundNeighbors = new ConcurrentLinkedDeque<String>();
142 inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
143 outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
145 complexGroups = new ArrayList<JsonNode>();
146 relationshipLists = new ArrayList<RelationshipList>();
147 nodeDepth = DEFAULT_INIT_NODE_DEPTH;
148 queryParams = new ArrayList<String>();
150 mapper = new ObjectMapper();
152 processedNeighbors = false;
153 resolvedSelfLink = false;
158 public void clearQueryParams() {
162 public void addQueryParam(String queryParam) {
163 if ( queryParam!= null) {
164 if( !queryParams.contains(queryParam)) {
165 queryParams.add(queryParam);
170 public void addInboundSelfLink(String link) {
176 if (!inboundNeighborSelfLinks.contains(link)) {
177 inboundNeighborSelfLinks.add(link);
182 public void addOutboundSelfLink(String link) {
188 if (!outboundNeighborSelfLinks.contains(link)) {
189 outboundNeighborSelfLinks.add(link);
194 public Collection<String> getInboundNeighborSelfLinks() {
195 return inboundNeighborSelfLinks;
198 public Collection<String> getOutboundNeighborSelfLinks() {
199 return outboundNeighborSelfLinks;
202 public void addQueryParams(Collection<String> params) {
204 if (params != null & params.size() > 0) {
206 for (String param : params) {
207 addQueryParam(param);
213 public List<String> getQueryParams() {
217 public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
218 this.selfLinkDeterminationPending = selfLinkDeterminationPending;
221 public boolean isSelfLinkDeterminationPending() {
222 return selfLinkDeterminationPending;
225 public NodeProcessingState getState() {
229 public List<JsonNode> getComplexGroups() {
230 return complexGroups;
233 public List<RelationshipList> getRelationshipLists() {
234 return relationshipLists;
237 public OperationResult getOpResult() {
241 public void setOpResult(OperationResult opResult) {
242 this.opResult = opResult;
245 public String getPrimaryKeyName() {
246 return primaryKeyName;
250 * Gets the visualization config.
252 * @return the visualization config
254 public VisualizationConfigs getvisualizationConfigs() {
255 return visualizationConfigs;
258 public int getNodeDepth() {
262 public void setNodeDepth(int nodeDepth) {
263 this.nodeDepth = nodeDepth;
267 * Sets the visualization config.
269 * @param visualizationConfig the new visualization config
271 public void setvisualizationConfig(VisualizationConfigs visualizationConfigs) {
272 this.visualizationConfigs = visualizationConfigs;
275 public OxmModelLoader getOxmModelLoader() {
276 return oxmModelLoader;
279 public void setPrimaryKeyName(String primaryKeyName) {
280 this.primaryKeyName = primaryKeyName;
283 public String getPrimaryKeyValue() {
284 return primaryKeyValue;
287 public void setPrimaryKeyValue(String primaryKeyValue) {
288 this.primaryKeyValue = primaryKeyValue;
291 public boolean isNodeValidated() {
292 return nodeValidated;
295 public void setNodeValidated(boolean nodeValidated) {
296 this.nodeValidated = nodeValidated;
299 public boolean isNodeIssue() {
303 public boolean isIgnoredByFilter() {
304 return ignoredByFilter;
307 public void setIgnoredByFilter(boolean ignoredByFilter) {
308 this.ignoredByFilter = ignoredByFilter;
311 public void setNodeIssue(boolean nodeIssue) {
312 this.nodeIssue = nodeIssue;
316 * Checks for processed neighbors.
318 * @return true, if successful
320 public boolean hasProcessedNeighbors() {
321 return processedNeighbors;
324 public void setProcessedNeighbors(boolean processedNeighbors) {
325 this.processedNeighbors = processedNeighbors;
329 * Checks for resolved self link.
331 * @return true, if successful
333 public boolean hasResolvedSelfLink() {
334 return resolvedSelfLink;
337 public void setResolvedSelfLink(boolean resolvedSelfLink) {
338 this.resolvedSelfLink = resolvedSelfLink;
342 * Checks for neighbors.
344 * @return true, if successful
346 public boolean hasNeighbors() {
347 return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
351 * Adds the inbound neighbor.
353 * @param nodeId the node id
355 public void addInboundNeighbor(String nodeId) {
357 if (nodeId == null) {
361 if (!inboundNeighbors.contains(nodeId)) {
362 inboundNeighbors.add(nodeId);
368 * Adds the outbound neighbor.
370 * @param nodeId the node id
372 public void addOutboundNeighbor(String nodeId) {
374 if (nodeId == null) {
378 if (!outboundNeighbors.contains(nodeId)) {
379 outboundNeighbors.add(nodeId);
384 public boolean isAtMaxDepth() {
385 return (nodeDepth >= this.visualizationConfigs.getMaxSelfLinkTraversalDepth());
388 public ConcurrentLinkedDeque<String> getInboundNeighbors() {
389 return inboundNeighbors;
392 public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
393 this.inboundNeighbors = inboundNeighbors;
396 public Collection<String> getOutboundNeighbors() {
397 List<String> result = new ArrayList<String>();
399 Iterator<String> neighborIterator = outboundNeighbors.iterator();
401 while (neighborIterator.hasNext()) {
402 result.add(neighborIterator.next());
411 * @param newDepth the new depth
412 * @return true, if successful
414 public boolean changeDepth(int newDepth) {
416 boolean nodeDepthWasChanged = false;
418 if (newDepth < nodeDepth) {
419 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
420 String.valueOf(this.nodeDepth), String.valueOf(newDepth));
421 this.nodeDepth = newDepth;
422 nodeDepthWasChanged = true;
425 return nodeDepthWasChanged;
429 public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
430 this.outboundNeighbors = outboundNeighbors;
433 public boolean isRootNode() {
437 public void setRootNode(boolean isRootNode) {
438 this.isRootNode = isRootNode;
444 * @param newState the new state
445 * @param action the action
447 public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
449 * NodeId may be null depending on the current node life-cycle state
452 if (getNodeId() != null) {
453 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
455 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
457 this.state = newState;
460 public boolean isSelfLinkPendingResolve() {
461 return selfLinkPendingResolve;
464 public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
465 this.selfLinkPendingResolve = selfLinkPendingResolve;
468 public boolean isSelflinkRetrievalFailure() {
469 return selflinkRetrievalFailure;
472 public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
473 this.selflinkRetrievalFailure = selflinkRetrievalFailure;
476 public void setOxmModelLoader(OxmModelLoader loader) {
477 this.oxmModelLoader = loader;
480 public boolean getSelfLinkProcessed() {
481 return selfLinkProcessed.get();
484 public void setSelfLinkProcessed(boolean selfLinkProcessed) {
485 this.selfLinkProcessed.set(selfLinkProcessed);
488 public boolean getNodeIntegrityProcessed() {
489 return nodeIntegrityProcessed.get();
492 public void setNodeIntegrityProcessed(boolean nodeIntegrityProcessed) {
493 this.nodeIntegrityProcessed.set(nodeIntegrityProcessed);
496 public boolean isDirectSelfLink() {
497 return isDirectSelfLink(this.selfLink);
501 * Checks if is direct self link.
503 * @param link the link
504 * @return true, if is direct self link
506 public static boolean isDirectSelfLink(String link) {
512 return link.contains("/resources/id/");
516 public Map<String, String> getProperties() {
521 * Adds the error cause.
523 * @param error the error
525 public void addErrorCause(String error) {
526 if (!errorCauses.contains(error)) {
527 errorCauses.add(error);
535 * @param value the value
537 public void addProperty(String key, String value) {
538 properties.put(key, value);
541 public boolean isProcessingErrorOccurred() {
542 return processingErrorOccurred;
545 public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
546 this.processingErrorOccurred = processingErrorOccurred;
549 public String getNodeId() {
553 public void setNodeId(String nodeId) {
554 this.nodeId = nodeId;
557 public String getEntityType() {
561 public void setEntityType(String entityType) {
562 this.entityType = entityType;
565 public String getSelfLink() {
570 * Analyze self link relationship list.
572 * @param jsonResult the json result
573 * @return the relationship list
575 private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
578 RelationshipList relationshipList = null;
581 relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
582 } catch (Exception exc) {
583 LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
586 return relationshipList;
590 * Adds the relationship list.
592 * @param relationshipList the relationship list
594 public void addRelationshipList(RelationshipList relationshipList) {
596 if (!relationshipLists.contains(relationshipList)) {
597 relationshipLists.add(relationshipList);
603 * Process pathed self link response.
605 * @param selfLinkJsonResponse the self link json response
606 * @param startNodeType the start node type
607 * @param startNodeResourceKey the start node resource key
609 public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
610 String startNodeResourceKey) {
612 if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
613 LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
618 JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
620 Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
621 Entry<String, JsonNode> field = null;
623 while (fieldNames.hasNext()) {
625 field = fieldNames.next();
628 * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
629 * flattening code needs to live
632 String fieldName = field.getKey();
634 if ("relationship-list".equals(fieldName)) {
637 * Parse the relationship list like we were doing before, so we can determine whether or
638 * not to keep it or traverse it after we have performed the evaluative node depth logic.
640 RelationshipList relationshipList =
641 analyzeSelfLinkRelationshipList(field.getValue().toString());
643 if (relationshipList != null) {
644 this.relationshipLists.add(relationshipList);
646 LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
649 JsonNode nodeValue = field.getValue();
651 if (nodeValue != null) {
652 if (nodeValue.isValueNode()) {
655 * before we blindly add the fieldName and value to our property set, let's do one more
656 * check to see if the field name is an entity type. If it is, then our complex
657 * attribute processing code will pick it up and process it instead, but this is
658 * probably more likely just for array node types, but we'll see.
661 handleNodeValue(fieldName, nodeValue.asText());
663 } else if (nodeValue.isArray()) {
666 * make sure array entity-type collection is not an entityType before adding it to the
667 * property set. The expetation is that it will be added the visualization through a
668 * complex group or relationship.
671 handleNodeValue(field.getKey(), nodeValue.toString());
673 complexGroups.add(nodeValue);
680 } catch (IOException exc) {
681 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
682 this.setProcessingErrorOccurred(true);
684 "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
689 private void handleNodeValue(String fieldName, String fieldValue) {
690 if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
692 * this is no an entity type as far as we can tell, so we can add it to our property
696 addProperty(fieldName, fieldValue);
701 public void setSelfLink(String selfLink) {
702 this.selfLink = selfLink;
706 * Adds the complex group.
708 * @param complexGroup the complex group
710 public void addComplexGroup(JsonNode complexGroup) {
712 if (!complexGroups.contains(complexGroup)) {
713 complexGroups.add(complexGroup);
721 * @param level the level
722 * @param paddingString the padding string
723 * @return the padding
725 private static String getPadding(int level, String paddingString) {
726 StringBuilder sb = new StringBuilder(32);
727 for (int x = 0; x < level; x++) {
728 sb.append(paddingString);
730 return sb.toString();
736 * @param showProperties the show properties
739 public String dumpNodeTree(boolean showProperties) {
740 return dumpNodeTree(0, showProperties);
746 * @param level the level
747 * @param showProperties the show properties
750 private String dumpNodeTree(int level, boolean showProperties) {
751 StringBuilder sb = new StringBuilder(128);
752 String padding = getPadding(level, " ");
754 sb.append(padding + " -> " + getNodeId() + "]").append("\n");
755 sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
756 sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
757 sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
759 if (showProperties) {
760 Set<Entry<String, String>> entries = properties.entrySet();
761 for (Entry<String, String> entry : entries) {
763 padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
768 sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
771 sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
773 for (String inboundNeighbor : inboundNeighbors) {
774 sb.append("\n").append(inboundNeighbor.toString());
777 sb.append(padding + " ----> Outbound Neighbors:").append("\n");
778 sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
780 for (String outboundNeighbor : outboundNeighbors) {
781 sb.append("\n").append(outboundNeighbor.toString());
784 return sb.toString();
788 public String getProcessingErrorCauses() {
790 StringBuilder sb = new StringBuilder(128);
792 for (String c : this.errorCauses) {
793 sb.append(c).append("\n");
796 return sb.toString();