2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.onap.aai.sparky.viewandinspect.entity;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
32 import java.util.Map.Entry;
34 import java.util.concurrent.ConcurrentLinkedDeque;
35 import java.util.concurrent.atomic.AtomicBoolean;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
39 import org.onap.aai.cl.api.Logger;
40 import org.onap.aai.cl.eelf.LoggerFactory;
41 import org.onap.aai.restclient.client.OperationResult;
42 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
43 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
44 import org.onap.aai.sparky.logging.AaiUiMsgs;
45 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
46 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
47 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
49 import com.fasterxml.jackson.databind.JsonNode;
50 import com.fasterxml.jackson.databind.ObjectMapper;
53 * The Class ActiveInventoryNode.
55 public class ActiveInventoryNode {
57 private static final Logger LOG = LoggerFactory.getInstance().getLogger(
58 ActiveInventoryNode.class);
59 private static final String URIRegexPattern = "aai/v[\\d]/";
61 public static final int DEFAULT_INIT_NODE_DEPTH = 1000;
63 private String nodeId;
64 private String selfLink;
66 private boolean isRootNode;
67 private ConcurrentLinkedDeque<String> inboundNeighbors;
68 private ConcurrentLinkedDeque<String> outboundNeighbors;
70 private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
71 private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
73 private List<JsonNode> complexGroups;
74 private List<RelationshipList> relationshipLists;
75 private int nodeDepth;
76 private OperationResult opResult;
78 private boolean processingErrorOccurred;
79 private List<String> errorCauses;
80 private boolean selflinkRetrievalFailure;
81 private NodeProcessingState state;
83 private boolean processedNeighbors;
85 private boolean selfLinkPendingResolve;
88 * I think we shouldn't be using this crutch flags. If these things are meant
89 * to represent the current state of the node, then they should be legitimate
93 private boolean selfLinkDeterminationPending;
95 private AtomicBoolean selfLinkProcessed;
96 private AtomicBoolean nodeIntegrityProcessed;
98 private OxmModelLoader oxmModelLoader;
99 private VisualizationConfigs visualizationConfigs;
101 private String entityType;
102 private String primaryKeyName;
103 private String primaryKeyValue;
105 private boolean nodeValidated;
106 private boolean nodeIssue;
107 private boolean ignoredByFilter;
109 private boolean resolvedSelfLink;
111 private Map<String, String> properties;
112 private ArrayList<String> queryParams;
114 private ObjectMapper mapper;
116 private OxmEntityLookup oxmEntityLookup;
119 * Instantiates a new active inventory node.
123 public ActiveInventoryNode(VisualizationConfigs visualizationConfigs, OxmEntityLookup oxmEntityLookup) {
124 this.oxmEntityLookup = oxmEntityLookup;
126 this.entityType = null;
127 this.selfLink = null;
128 this.properties = new HashMap<String, String>();
129 this.processingErrorOccurred = false;
130 this.errorCauses = new ArrayList<String>();
131 this.selflinkRetrievalFailure = false;
132 this.nodeIssue = false;
133 this.nodeValidated = false;
134 this.state = NodeProcessingState.INIT;
135 this.selfLinkPendingResolve = false;
136 this.selfLinkDeterminationPending = false;
138 selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
139 nodeIntegrityProcessed = new AtomicBoolean(Boolean.FALSE);
140 oxmModelLoader = null;
141 this.visualizationConfigs = visualizationConfigs ;
144 inboundNeighbors = new ConcurrentLinkedDeque<String>();
145 outboundNeighbors = new ConcurrentLinkedDeque<String>();
147 inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
148 outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
150 complexGroups = new ArrayList<JsonNode>();
151 relationshipLists = new ArrayList<RelationshipList>();
152 nodeDepth = DEFAULT_INIT_NODE_DEPTH;
153 queryParams = new ArrayList<String>();
155 mapper = new ObjectMapper();
157 processedNeighbors = false;
158 resolvedSelfLink = false;
163 public void clearQueryParams() {
167 public void addQueryParam(String queryParam) {
168 if ( queryParam!= null) {
169 if( !queryParams.contains(queryParam)) {
170 queryParams.add(queryParam);
175 public void addInboundSelfLink(String link) {
181 if (!inboundNeighborSelfLinks.contains(link)) {
182 inboundNeighborSelfLinks.add(link);
187 public void addOutboundSelfLink(String link) {
193 if (!outboundNeighborSelfLinks.contains(link)) {
194 outboundNeighborSelfLinks.add(link);
199 public Collection<String> getInboundNeighborSelfLinks() {
200 return inboundNeighborSelfLinks;
203 public Collection<String> getOutboundNeighborSelfLinks() {
204 return outboundNeighborSelfLinks;
207 public void addQueryParams(Collection<String> params) {
209 if (params != null & params.size() > 0) {
211 for (String param : params) {
212 addQueryParam(param);
218 public List<String> getQueryParams() {
222 public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
223 this.selfLinkDeterminationPending = selfLinkDeterminationPending;
226 public boolean isSelfLinkDeterminationPending() {
227 return selfLinkDeterminationPending;
230 public NodeProcessingState getState() {
234 public List<JsonNode> getComplexGroups() {
235 return complexGroups;
238 public List<RelationshipList> getRelationshipLists() {
239 return relationshipLists;
242 public OperationResult getOpResult() {
246 public void setOpResult(OperationResult opResult) {
247 this.opResult = opResult;
250 public String getPrimaryKeyName() {
251 return primaryKeyName;
255 * Gets the visualization config.
257 * @return the visualization config
259 public VisualizationConfigs getvisualizationConfigs() {
260 return visualizationConfigs;
263 public int getNodeDepth() {
267 public void setNodeDepth(int nodeDepth) {
268 this.nodeDepth = nodeDepth;
272 * Sets the visualization config.
274 * @param visualizationConfig the new visualization config
276 public void setvisualizationConfig(VisualizationConfigs visualizationConfigs) {
277 this.visualizationConfigs = visualizationConfigs;
280 public OxmModelLoader getOxmModelLoader() {
281 return oxmModelLoader;
284 public void setPrimaryKeyName(String primaryKeyName) {
285 this.primaryKeyName = primaryKeyName;
288 public String getPrimaryKeyValue() {
289 return primaryKeyValue;
292 public void setPrimaryKeyValue(String primaryKeyValue) {
293 this.primaryKeyValue = primaryKeyValue;
296 public boolean isNodeValidated() {
297 return nodeValidated;
300 public void setNodeValidated(boolean nodeValidated) {
301 this.nodeValidated = nodeValidated;
304 public boolean isNodeIssue() {
308 public boolean isIgnoredByFilter() {
309 return ignoredByFilter;
312 public void setIgnoredByFilter(boolean ignoredByFilter) {
313 this.ignoredByFilter = ignoredByFilter;
316 public void setNodeIssue(boolean nodeIssue) {
317 this.nodeIssue = nodeIssue;
321 * Checks for processed neighbors.
323 * @return true, if successful
325 public boolean hasProcessedNeighbors() {
326 return processedNeighbors;
329 public void setProcessedNeighbors(boolean processedNeighbors) {
330 this.processedNeighbors = processedNeighbors;
334 * Checks for resolved self link.
336 * @return true, if successful
338 public boolean hasResolvedSelfLink() {
339 return resolvedSelfLink;
342 public void setResolvedSelfLink(boolean resolvedSelfLink) {
343 this.resolvedSelfLink = resolvedSelfLink;
347 * Checks for neighbors.
349 * @return true, if successful
351 public boolean hasNeighbors() {
352 return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
356 * Adds the inbound neighbor.
358 * @param nodeId the node id
360 public void addInboundNeighbor(String nodeId) {
362 if (nodeId == null) {
366 if (!inboundNeighbors.contains(nodeId)) {
367 inboundNeighbors.add(nodeId);
373 * Adds the outbound neighbor.
375 * @param nodeId the node id
377 public void addOutboundNeighbor(String nodeId) {
379 if (nodeId == null) {
383 if (!outboundNeighbors.contains(nodeId)) {
384 outboundNeighbors.add(nodeId);
389 public boolean isAtMaxDepth() {
390 return (nodeDepth >= this.visualizationConfigs.getMaxSelfLinkTraversalDepth());
393 public ConcurrentLinkedDeque<String> getInboundNeighbors() {
394 return inboundNeighbors;
397 public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
398 this.inboundNeighbors = inboundNeighbors;
401 public Collection<String> getOutboundNeighbors() {
402 List<String> result = new ArrayList<String>();
404 Iterator<String> neighborIterator = outboundNeighbors.iterator();
406 while (neighborIterator.hasNext()) {
407 result.add(neighborIterator.next());
416 * @param newDepth the new depth
417 * @return true, if successful
419 public boolean changeDepth(int newDepth) {
421 boolean nodeDepthWasChanged = false;
423 if (newDepth < nodeDepth) {
424 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
425 String.valueOf(this.nodeDepth), String.valueOf(newDepth));
426 this.nodeDepth = newDepth;
427 nodeDepthWasChanged = true;
430 return nodeDepthWasChanged;
434 public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
435 this.outboundNeighbors = outboundNeighbors;
438 public boolean isRootNode() {
442 public void setRootNode(boolean isRootNode) {
443 this.isRootNode = isRootNode;
449 * @param newState the new state
450 * @param action the action
452 public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
454 * NodeId may be null depending on the current node life-cycle state
457 if (getNodeId() != null) {
458 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
460 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
462 this.state = newState;
465 public boolean isSelfLinkPendingResolve() {
466 return selfLinkPendingResolve;
469 public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
470 this.selfLinkPendingResolve = selfLinkPendingResolve;
473 public boolean isSelflinkRetrievalFailure() {
474 return selflinkRetrievalFailure;
477 public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
478 this.selflinkRetrievalFailure = selflinkRetrievalFailure;
481 public void setOxmModelLoader(OxmModelLoader loader) {
482 this.oxmModelLoader = loader;
485 public boolean getSelfLinkProcessed() {
486 return selfLinkProcessed.get();
489 public void setSelfLinkProcessed(boolean selfLinkProcessed) {
490 this.selfLinkProcessed.set(selfLinkProcessed);
493 public boolean getNodeIntegrityProcessed() {
494 return nodeIntegrityProcessed.get();
497 public void setNodeIntegrityProcessed(boolean nodeIntegrityProcessed) {
498 this.nodeIntegrityProcessed.set(nodeIntegrityProcessed);
501 public boolean isDirectSelfLink() {
502 return isDirectSelfLink(this.selfLink);
506 * Checks if is direct self link.
508 * @param link the link
509 * @return true, if is direct self link
511 public static boolean isDirectSelfLink(String link) {
517 return link.contains("/resources/id/");
521 public Map<String, String> getProperties() {
526 * Adds the error cause.
528 * @param error the error
530 public void addErrorCause(String error) {
531 if (!errorCauses.contains(error)) {
532 errorCauses.add(error);
540 * @param value the value
542 public void addProperty(String key, String value) {
543 properties.put(key, value);
546 public boolean isProcessingErrorOccurred() {
547 return processingErrorOccurred;
550 public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
551 this.processingErrorOccurred = processingErrorOccurred;
554 public String getNodeId() {
558 public void setNodeId(String nodeId) {
559 this.nodeId = nodeId;
562 public String getEntityType() {
566 public void setEntityType(String entityType) {
567 this.entityType = entityType;
570 public String getSelfLink() {
575 * Calculate edit attribute uri.
577 * @param link the link
580 public String calculateEditAttributeUri(String link) {
582 Pattern pattern = Pattern.compile(URIRegexPattern);
583 Matcher matcher = pattern.matcher(link);
584 if (matcher.find()) {
585 uri = link.substring(matcher.end());
591 * Analyze self link relationship list.
593 * @param jsonResult the json result
594 * @return the relationship list
596 private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
599 RelationshipList relationshipList = null;
602 relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
603 } catch (Exception exc) {
604 LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
607 return relationshipList;
611 * Adds the relationship list.
613 * @param relationshipList the relationship list
615 public void addRelationshipList(RelationshipList relationshipList) {
617 if (!relationshipLists.contains(relationshipList)) {
618 relationshipLists.add(relationshipList);
624 * Process pathed self link response.
626 * @param selfLinkJsonResponse the self link json response
627 * @param startNodeType the start node type
628 * @param startNodeResourceKey the start node resource key
630 public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
631 String startNodeResourceKey) {
633 if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
634 LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
639 JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
641 Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
642 Entry<String, JsonNode> field = null;
644 while (fieldNames.hasNext()) {
646 field = fieldNames.next();
649 * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
650 * flattening code needs to live
653 String fieldName = field.getKey();
655 if ("relationship-list".equals(fieldName)) {
658 * Parse the relationship list like we were doing before, so we can determine whether or
659 * not to keep it or traverse it after we have performed the evaluative node depth logic.
661 RelationshipList relationshipList =
662 analyzeSelfLinkRelationshipList(field.getValue().toString());
664 if (relationshipList != null) {
665 this.relationshipLists.add(relationshipList);
667 LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
670 JsonNode nodeValue = field.getValue();
672 if (nodeValue != null && nodeValue.isValueNode()) {
675 * before we blindly add the fieldName and value to our property set, let's do one more
676 * check to see if the field name is an entity type. If it is, then our complex
677 * attribute processing code will pick it up and process it instead, but this is
678 * probably more likely just for array node types, but we'll see.
681 if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
683 * this is no an entity type as far as we can tell, so we can add it to our property
687 addProperty(fieldName, nodeValue.asText());
693 if (nodeValue.isArray()) {
696 * make sure array entity-type collection is not an entityType before adding it to the
697 * property set. The expetation is that it will be added the visualization through a
698 * complex group or relationship.
701 if (oxmEntityLookup.getEntityDescriptors().get(field.getKey()) == null) {
703 * this is no an entity type as far as we can tell, so we can add it to our property
707 addProperty(field.getKey(), nodeValue.toString());
713 complexGroups.add(nodeValue);
723 } catch (IOException exc) {
724 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
725 this.setProcessingErrorOccurred(true);
727 "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
732 public void setSelfLink(String selfLink) {
733 this.selfLink = selfLink;
737 * Adds the complex group.
739 * @param complexGroup the complex group
741 public void addComplexGroup(JsonNode complexGroup) {
743 if (!complexGroups.contains(complexGroup)) {
744 complexGroups.add(complexGroup);
752 * @param level the level
753 * @param paddingString the padding string
754 * @return the padding
756 private static String getPadding(int level, String paddingString) {
757 StringBuilder sb = new StringBuilder(32);
758 for (int x = 0; x < level; x++) {
759 sb.append(paddingString);
761 return sb.toString();
767 * @param showProperties the show properties
770 public String dumpNodeTree(boolean showProperties) {
771 return dumpNodeTree(0, showProperties);
777 * @param level the level
778 * @param showProperties the show properties
781 private String dumpNodeTree(int level, boolean showProperties) {
782 StringBuilder sb = new StringBuilder(128);
783 String padding = getPadding(level, " ");
785 sb.append(padding + " -> " + getNodeId() + "]").append("\n");
786 sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
787 sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
788 sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
790 if (showProperties) {
791 Set<Entry<String, String>> entries = properties.entrySet();
792 for (Entry<String, String> entry : entries) {
794 padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
799 sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
802 sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
804 for (String inboundNeighbor : inboundNeighbors) {
805 sb.append("\n").append(inboundNeighbor.toString());
808 sb.append(padding + " ----> Outbound Neighbors:").append("\n");
809 sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
811 for (String outboundNeighbor : outboundNeighbors) {
812 sb.append("\n").append(outboundNeighbor.toString());
815 return sb.toString();
819 public String getProcessingErrorCauses() {
821 StringBuilder sb = new StringBuilder(128);
823 for (String c : this.errorCauses) {
824 sb.append(c).append("\n");
827 return sb.toString();