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;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
37 import org.onap.aai.cl.api.Logger;
38 import org.onap.aai.cl.eelf.LoggerFactory;
39 import org.onap.aai.restclient.client.OperationResult;
40 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
41 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
42 import org.onap.aai.sparky.logging.AaiUiMsgs;
43 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
44 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
45 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
47 import com.fasterxml.jackson.databind.JsonNode;
48 import com.fasterxml.jackson.databind.ObjectMapper;
51 * The Class ActiveInventoryNode.
53 public class ActiveInventoryNode {
55 private static final Logger LOG = LoggerFactory.getInstance().getLogger(
56 ActiveInventoryNode.class);
57 private static final String URIRegexPattern = "aai/v[\\d]/";
59 public static final int DEFAULT_INIT_NODE_DEPTH = 1000;
61 private String nodeId;
62 private String selfLink;
64 private boolean isRootNode;
65 private ConcurrentLinkedDeque<String> inboundNeighbors;
66 private ConcurrentLinkedDeque<String> outboundNeighbors;
68 private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
69 private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
71 private List<JsonNode> complexGroups;
72 private List<RelationshipList> relationshipLists;
73 private int nodeDepth;
74 private OperationResult opResult;
76 private boolean processingErrorOccurred;
77 private List<String> errorCauses;
78 private boolean selflinkRetrievalFailure;
79 private NodeProcessingState state;
81 private boolean processedNeighbors;
83 private boolean selfLinkPendingResolve;
86 * I think we shouldn't be using this crutch flags. If these things are meant
87 * to represent the current state of the node, then they should be legitimate
91 private boolean selfLinkDeterminationPending;
93 private AtomicBoolean selfLinkProcessed;
94 private AtomicBoolean nodeIntegrityProcessed;
96 private OxmModelLoader oxmModelLoader;
97 private VisualizationConfigs visualizationConfigs;
99 private String entityType;
100 private String primaryKeyName;
101 private String primaryKeyValue;
103 private boolean nodeValidated;
104 private boolean nodeIssue;
105 private boolean ignoredByFilter;
107 private boolean resolvedSelfLink;
109 private Map<String, String> properties;
110 private ArrayList<String> queryParams;
112 private ObjectMapper mapper;
114 private OxmEntityLookup oxmEntityLookup;
117 * Instantiates a new active inventory node.
121 public ActiveInventoryNode(VisualizationConfigs visualizationConfigs, OxmEntityLookup oxmEntityLookup) {
122 this.oxmEntityLookup = oxmEntityLookup;
124 this.entityType = null;
125 this.selfLink = null;
126 this.properties = new HashMap<String, String>();
127 this.processingErrorOccurred = false;
128 this.errorCauses = new ArrayList<String>();
129 this.selflinkRetrievalFailure = false;
130 this.nodeIssue = false;
131 this.nodeValidated = false;
132 this.state = NodeProcessingState.INIT;
133 this.selfLinkPendingResolve = false;
134 this.selfLinkDeterminationPending = false;
136 selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
137 nodeIntegrityProcessed = new AtomicBoolean(Boolean.FALSE);
138 oxmModelLoader = null;
139 this.visualizationConfigs = visualizationConfigs ;
142 inboundNeighbors = new ConcurrentLinkedDeque<String>();
143 outboundNeighbors = new ConcurrentLinkedDeque<String>();
145 inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
146 outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
148 complexGroups = new ArrayList<JsonNode>();
149 relationshipLists = new ArrayList<RelationshipList>();
150 nodeDepth = DEFAULT_INIT_NODE_DEPTH;
151 queryParams = new ArrayList<String>();
153 mapper = new ObjectMapper();
155 processedNeighbors = false;
156 resolvedSelfLink = false;
161 public void clearQueryParams() {
165 public void addQueryParam(String queryParam) {
166 if ( queryParam!= null) {
167 if( !queryParams.contains(queryParam)) {
168 queryParams.add(queryParam);
173 public void addInboundSelfLink(String link) {
179 if (!inboundNeighborSelfLinks.contains(link)) {
180 inboundNeighborSelfLinks.add(link);
185 public void addOutboundSelfLink(String link) {
191 if (!outboundNeighborSelfLinks.contains(link)) {
192 outboundNeighborSelfLinks.add(link);
197 public Collection<String> getInboundNeighborSelfLinks() {
198 return inboundNeighborSelfLinks;
201 public Collection<String> getOutboundNeighborSelfLinks() {
202 return outboundNeighborSelfLinks;
205 public void addQueryParams(Collection<String> params) {
207 if (params != null & params.size() > 0) {
209 for (String param : params) {
210 addQueryParam(param);
216 public List<String> getQueryParams() {
220 public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
221 this.selfLinkDeterminationPending = selfLinkDeterminationPending;
224 public boolean isSelfLinkDeterminationPending() {
225 return selfLinkDeterminationPending;
228 public NodeProcessingState getState() {
232 public List<JsonNode> getComplexGroups() {
233 return complexGroups;
236 public List<RelationshipList> getRelationshipLists() {
237 return relationshipLists;
240 public OperationResult getOpResult() {
244 public void setOpResult(OperationResult opResult) {
245 this.opResult = opResult;
248 public String getPrimaryKeyName() {
249 return primaryKeyName;
253 * Gets the visualization config.
255 * @return the visualization config
257 public VisualizationConfigs getvisualizationConfigs() {
258 return visualizationConfigs;
261 public int getNodeDepth() {
265 public void setNodeDepth(int nodeDepth) {
266 this.nodeDepth = nodeDepth;
270 * Sets the visualization config.
272 * @param visualizationConfig the new visualization config
274 public void setvisualizationConfig(VisualizationConfigs visualizationConfigs) {
275 this.visualizationConfigs = visualizationConfigs;
278 public OxmModelLoader getOxmModelLoader() {
279 return oxmModelLoader;
282 public void setPrimaryKeyName(String primaryKeyName) {
283 this.primaryKeyName = primaryKeyName;
286 public String getPrimaryKeyValue() {
287 return primaryKeyValue;
290 public void setPrimaryKeyValue(String primaryKeyValue) {
291 this.primaryKeyValue = primaryKeyValue;
294 public boolean isNodeValidated() {
295 return nodeValidated;
298 public void setNodeValidated(boolean nodeValidated) {
299 this.nodeValidated = nodeValidated;
302 public boolean isNodeIssue() {
306 public boolean isIgnoredByFilter() {
307 return ignoredByFilter;
310 public void setIgnoredByFilter(boolean ignoredByFilter) {
311 this.ignoredByFilter = ignoredByFilter;
314 public void setNodeIssue(boolean nodeIssue) {
315 this.nodeIssue = nodeIssue;
319 * Checks for processed neighbors.
321 * @return true, if successful
323 public boolean hasProcessedNeighbors() {
324 return processedNeighbors;
327 public void setProcessedNeighbors(boolean processedNeighbors) {
328 this.processedNeighbors = processedNeighbors;
332 * Checks for resolved self link.
334 * @return true, if successful
336 public boolean hasResolvedSelfLink() {
337 return resolvedSelfLink;
340 public void setResolvedSelfLink(boolean resolvedSelfLink) {
341 this.resolvedSelfLink = resolvedSelfLink;
345 * Checks for neighbors.
347 * @return true, if successful
349 public boolean hasNeighbors() {
350 return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
354 * Adds the inbound neighbor.
356 * @param nodeId the node id
358 public void addInboundNeighbor(String nodeId) {
360 if (nodeId == null) {
364 if (!inboundNeighbors.contains(nodeId)) {
365 inboundNeighbors.add(nodeId);
371 * Adds the outbound neighbor.
373 * @param nodeId the node id
375 public void addOutboundNeighbor(String nodeId) {
377 if (nodeId == null) {
381 if (!outboundNeighbors.contains(nodeId)) {
382 outboundNeighbors.add(nodeId);
387 public boolean isAtMaxDepth() {
388 return (nodeDepth >= this.visualizationConfigs.getMaxSelfLinkTraversalDepth());
391 public ConcurrentLinkedDeque<String> getInboundNeighbors() {
392 return inboundNeighbors;
395 public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
396 this.inboundNeighbors = inboundNeighbors;
399 public Collection<String> getOutboundNeighbors() {
400 List<String> result = new ArrayList<String>();
402 Iterator<String> neighborIterator = outboundNeighbors.iterator();
404 while (neighborIterator.hasNext()) {
405 result.add(neighborIterator.next());
414 * @param newDepth the new depth
415 * @return true, if successful
417 public boolean changeDepth(int newDepth) {
419 boolean nodeDepthWasChanged = false;
421 if (newDepth < nodeDepth) {
422 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
423 String.valueOf(this.nodeDepth), String.valueOf(newDepth));
424 this.nodeDepth = newDepth;
425 nodeDepthWasChanged = true;
428 return nodeDepthWasChanged;
432 public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
433 this.outboundNeighbors = outboundNeighbors;
436 public boolean isRootNode() {
440 public void setRootNode(boolean isRootNode) {
441 this.isRootNode = isRootNode;
447 * @param newState the new state
448 * @param action the action
450 public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
452 * NodeId may be null depending on the current node life-cycle state
455 if (getNodeId() != null) {
456 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
458 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
460 this.state = newState;
463 public boolean isSelfLinkPendingResolve() {
464 return selfLinkPendingResolve;
467 public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
468 this.selfLinkPendingResolve = selfLinkPendingResolve;
471 public boolean isSelflinkRetrievalFailure() {
472 return selflinkRetrievalFailure;
475 public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
476 this.selflinkRetrievalFailure = selflinkRetrievalFailure;
479 public void setOxmModelLoader(OxmModelLoader loader) {
480 this.oxmModelLoader = loader;
483 public boolean getSelfLinkProcessed() {
484 return selfLinkProcessed.get();
487 public void setSelfLinkProcessed(boolean selfLinkProcessed) {
488 this.selfLinkProcessed.set(selfLinkProcessed);
491 public boolean getNodeIntegrityProcessed() {
492 return nodeIntegrityProcessed.get();
495 public void setNodeIntegrityProcessed(boolean nodeIntegrityProcessed) {
496 this.nodeIntegrityProcessed.set(nodeIntegrityProcessed);
499 public boolean isDirectSelfLink() {
500 return isDirectSelfLink(this.selfLink);
504 * Checks if is direct self link.
506 * @param link the link
507 * @return true, if is direct self link
509 public static boolean isDirectSelfLink(String link) {
515 return link.contains("/resources/id/");
519 public Map<String, String> getProperties() {
524 * Adds the error cause.
526 * @param error the error
528 public void addErrorCause(String error) {
529 if (!errorCauses.contains(error)) {
530 errorCauses.add(error);
538 * @param value the value
540 public void addProperty(String key, String value) {
541 properties.put(key, value);
544 public boolean isProcessingErrorOccurred() {
545 return processingErrorOccurred;
548 public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
549 this.processingErrorOccurred = processingErrorOccurred;
552 public String getNodeId() {
556 public void setNodeId(String nodeId) {
557 this.nodeId = nodeId;
560 public String getEntityType() {
564 public void setEntityType(String entityType) {
565 this.entityType = entityType;
568 public String getSelfLink() {
573 * Calculate edit attribute uri.
575 * @param link the link
578 public String calculateEditAttributeUri(String link) {
580 Pattern pattern = Pattern.compile(URIRegexPattern);
581 Matcher matcher = pattern.matcher(link);
582 if (matcher.find()) {
583 uri = link.substring(matcher.end());
589 * Analyze self link relationship list.
591 * @param jsonResult the json result
592 * @return the relationship list
594 private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
597 RelationshipList relationshipList = null;
600 relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
601 } catch (Exception exc) {
602 LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
605 return relationshipList;
609 * Adds the relationship list.
611 * @param relationshipList the relationship list
613 public void addRelationshipList(RelationshipList relationshipList) {
615 if (!relationshipLists.contains(relationshipList)) {
616 relationshipLists.add(relationshipList);
622 * Process pathed self link response.
624 * @param selfLinkJsonResponse the self link json response
625 * @param startNodeType the start node type
626 * @param startNodeResourceKey the start node resource key
628 public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
629 String startNodeResourceKey) {
631 if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
632 LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
637 JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
639 Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
640 Entry<String, JsonNode> field = null;
642 while (fieldNames.hasNext()) {
644 field = fieldNames.next();
647 * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
648 * flattening code needs to live
651 String fieldName = field.getKey();
653 if ("relationship-list".equals(fieldName)) {
656 * Parse the relationship list like we were doing before, so we can determine whether or
657 * not to keep it or traverse it after we have performed the evaluative node depth logic.
659 RelationshipList relationshipList =
660 analyzeSelfLinkRelationshipList(field.getValue().toString());
662 if (relationshipList != null) {
663 this.relationshipLists.add(relationshipList);
665 LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
668 JsonNode nodeValue = field.getValue();
670 if (nodeValue != null) {
671 if (nodeValue.isValueNode()) {
674 * before we blindly add the fieldName and value to our property set, let's do one more
675 * check to see if the field name is an entity type. If it is, then our complex
676 * attribute processing code will pick it up and process it instead, but this is
677 * probably more likely just for array node types, but we'll see.
680 handleNodeValue(fieldName, nodeValue.asText());
682 } else if (nodeValue.isArray()) {
685 * make sure array entity-type collection is not an entityType before adding it to the
686 * property set. The expetation is that it will be added the visualization through a
687 * complex group or relationship.
690 handleNodeValue(field.getKey(), nodeValue.toString());
692 complexGroups.add(nodeValue);
699 } catch (IOException exc) {
700 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
701 this.setProcessingErrorOccurred(true);
703 "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
708 private void handleNodeValue(String fieldName, String fieldValue) {
709 if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
711 * this is no an entity type as far as we can tell, so we can add it to our property
715 addProperty(fieldName, fieldValue);
720 public void setSelfLink(String selfLink) {
721 this.selfLink = selfLink;
725 * Adds the complex group.
727 * @param complexGroup the complex group
729 public void addComplexGroup(JsonNode complexGroup) {
731 if (!complexGroups.contains(complexGroup)) {
732 complexGroups.add(complexGroup);
740 * @param level the level
741 * @param paddingString the padding string
742 * @return the padding
744 private static String getPadding(int level, String paddingString) {
745 StringBuilder sb = new StringBuilder(32);
746 for (int x = 0; x < level; x++) {
747 sb.append(paddingString);
749 return sb.toString();
755 * @param showProperties the show properties
758 public String dumpNodeTree(boolean showProperties) {
759 return dumpNodeTree(0, showProperties);
765 * @param level the level
766 * @param showProperties the show properties
769 private String dumpNodeTree(int level, boolean showProperties) {
770 StringBuilder sb = new StringBuilder(128);
771 String padding = getPadding(level, " ");
773 sb.append(padding + " -> " + getNodeId() + "]").append("\n");
774 sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
775 sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
776 sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
778 if (showProperties) {
779 Set<Entry<String, String>> entries = properties.entrySet();
780 for (Entry<String, String> entry : entries) {
782 padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
787 sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
790 sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
792 for (String inboundNeighbor : inboundNeighbors) {
793 sb.append("\n").append(inboundNeighbor.toString());
796 sb.append(padding + " ----> Outbound Neighbors:").append("\n");
797 sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
799 for (String outboundNeighbor : outboundNeighbors) {
800 sb.append("\n").append(outboundNeighbor.toString());
803 return sb.toString();
807 public String getProcessingErrorCauses() {
809 StringBuilder sb = new StringBuilder(128);
811 for (String c : this.errorCauses) {
812 sb.append(c).append("\n");
815 return sb.toString();