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.entity;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
34 import java.util.Map.Entry;
36 import java.util.concurrent.ConcurrentLinkedDeque;
37 import java.util.concurrent.atomic.AtomicBoolean;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
41 import org.onap.aai.cl.api.Logger;
42 import org.onap.aai.cl.eelf.LoggerFactory;
43 import org.onap.aai.restclient.client.OperationResult;
44 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
45 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
46 import org.onap.aai.sparky.logging.AaiUiMsgs;
47 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
48 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
49 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
51 import com.fasterxml.jackson.databind.JsonNode;
52 import com.fasterxml.jackson.databind.ObjectMapper;
55 * The Class ActiveInventoryNode.
57 public class ActiveInventoryNode {
59 private static final Logger LOG = LoggerFactory.getInstance().getLogger(
60 ActiveInventoryNode.class);
61 private static final String URIRegexPattern = "aai/v[\\d]/";
63 public static final int DEFAULT_INIT_NODE_DEPTH = 1000;
65 private String nodeId;
66 private String selfLink;
68 private boolean isRootNode;
69 private ConcurrentLinkedDeque<String> inboundNeighbors;
70 private ConcurrentLinkedDeque<String> outboundNeighbors;
72 private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
73 private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
75 private List<JsonNode> complexGroups;
76 private List<RelationshipList> relationshipLists;
77 private int nodeDepth;
78 private OperationResult opResult;
80 private boolean processingErrorOccurred;
81 private List<String> errorCauses;
82 private boolean selflinkRetrievalFailure;
83 private NodeProcessingState state;
85 private boolean processedNeighbors;
87 private boolean selfLinkPendingResolve;
90 * I think we shouldn't be using this crutch flags. If these things are meant
91 * to represent the current state of the node, then they should be legitimate
95 private boolean selfLinkDeterminationPending;
97 private AtomicBoolean selfLinkProcessed;
98 private AtomicBoolean nodeIntegrityProcessed;
100 private OxmModelLoader oxmModelLoader;
101 private VisualizationConfigs visualizationConfigs;
103 private String entityType;
104 private String primaryKeyName;
105 private String primaryKeyValue;
107 private boolean nodeValidated;
108 private boolean nodeIssue;
109 private boolean ignoredByFilter;
111 private boolean resolvedSelfLink;
113 private Map<String, String> properties;
114 private ArrayList<String> queryParams;
116 private ObjectMapper mapper;
118 private OxmEntityLookup oxmEntityLookup;
121 * Instantiates a new active inventory node.
125 public ActiveInventoryNode(VisualizationConfigs visualizationConfigs, OxmEntityLookup oxmEntityLookup) {
126 this.oxmEntityLookup = oxmEntityLookup;
128 this.entityType = null;
129 this.selfLink = null;
130 this.properties = new HashMap<String, String>();
131 this.processingErrorOccurred = false;
132 this.errorCauses = new ArrayList<String>();
133 this.selflinkRetrievalFailure = false;
134 this.nodeIssue = false;
135 this.nodeValidated = false;
136 this.state = NodeProcessingState.INIT;
137 this.selfLinkPendingResolve = false;
138 this.selfLinkDeterminationPending = false;
140 selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
141 nodeIntegrityProcessed = new AtomicBoolean(Boolean.FALSE);
142 oxmModelLoader = null;
143 this.visualizationConfigs = visualizationConfigs ;
146 inboundNeighbors = new ConcurrentLinkedDeque<String>();
147 outboundNeighbors = new ConcurrentLinkedDeque<String>();
149 inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
150 outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
152 complexGroups = new ArrayList<JsonNode>();
153 relationshipLists = new ArrayList<RelationshipList>();
154 nodeDepth = DEFAULT_INIT_NODE_DEPTH;
155 queryParams = new ArrayList<String>();
157 mapper = new ObjectMapper();
159 processedNeighbors = false;
160 resolvedSelfLink = false;
165 public void clearQueryParams() {
169 public void addQueryParam(String queryParam) {
170 if ( queryParam!= null) {
171 if( !queryParams.contains(queryParam)) {
172 queryParams.add(queryParam);
177 public void addInboundSelfLink(String link) {
183 if (!inboundNeighborSelfLinks.contains(link)) {
184 inboundNeighborSelfLinks.add(link);
189 public void addOutboundSelfLink(String link) {
195 if (!outboundNeighborSelfLinks.contains(link)) {
196 outboundNeighborSelfLinks.add(link);
201 public Collection<String> getInboundNeighborSelfLinks() {
202 return inboundNeighborSelfLinks;
205 public Collection<String> getOutboundNeighborSelfLinks() {
206 return outboundNeighborSelfLinks;
209 public void addQueryParams(Collection<String> params) {
211 if (params != null & params.size() > 0) {
213 for (String param : params) {
214 addQueryParam(param);
220 public List<String> getQueryParams() {
224 public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
225 this.selfLinkDeterminationPending = selfLinkDeterminationPending;
228 public boolean isSelfLinkDeterminationPending() {
229 return selfLinkDeterminationPending;
232 public NodeProcessingState getState() {
236 public List<JsonNode> getComplexGroups() {
237 return complexGroups;
240 public List<RelationshipList> getRelationshipLists() {
241 return relationshipLists;
244 public OperationResult getOpResult() {
248 public void setOpResult(OperationResult opResult) {
249 this.opResult = opResult;
252 public String getPrimaryKeyName() {
253 return primaryKeyName;
257 * Gets the visualization config.
259 * @return the visualization config
261 public VisualizationConfigs getvisualizationConfigs() {
262 return visualizationConfigs;
265 public int getNodeDepth() {
269 public void setNodeDepth(int nodeDepth) {
270 this.nodeDepth = nodeDepth;
274 * Sets the visualization config.
276 * @param visualizationConfig the new visualization config
278 public void setvisualizationConfig(VisualizationConfigs visualizationConfigs) {
279 this.visualizationConfigs = visualizationConfigs;
282 public OxmModelLoader getOxmModelLoader() {
283 return oxmModelLoader;
286 public void setPrimaryKeyName(String primaryKeyName) {
287 this.primaryKeyName = primaryKeyName;
290 public String getPrimaryKeyValue() {
291 return primaryKeyValue;
294 public void setPrimaryKeyValue(String primaryKeyValue) {
295 this.primaryKeyValue = primaryKeyValue;
298 public boolean isNodeValidated() {
299 return nodeValidated;
302 public void setNodeValidated(boolean nodeValidated) {
303 this.nodeValidated = nodeValidated;
306 public boolean isNodeIssue() {
310 public boolean isIgnoredByFilter() {
311 return ignoredByFilter;
314 public void setIgnoredByFilter(boolean ignoredByFilter) {
315 this.ignoredByFilter = ignoredByFilter;
318 public void setNodeIssue(boolean nodeIssue) {
319 this.nodeIssue = nodeIssue;
323 * Checks for processed neighbors.
325 * @return true, if successful
327 public boolean hasProcessedNeighbors() {
328 return processedNeighbors;
331 public void setProcessedNeighbors(boolean processedNeighbors) {
332 this.processedNeighbors = processedNeighbors;
336 * Checks for resolved self link.
338 * @return true, if successful
340 public boolean hasResolvedSelfLink() {
341 return resolvedSelfLink;
344 public void setResolvedSelfLink(boolean resolvedSelfLink) {
345 this.resolvedSelfLink = resolvedSelfLink;
349 * Checks for neighbors.
351 * @return true, if successful
353 public boolean hasNeighbors() {
354 return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
358 * Adds the inbound neighbor.
360 * @param nodeId the node id
362 public void addInboundNeighbor(String nodeId) {
364 if (nodeId == null) {
368 if (!inboundNeighbors.contains(nodeId)) {
369 inboundNeighbors.add(nodeId);
375 * Adds the outbound neighbor.
377 * @param nodeId the node id
379 public void addOutboundNeighbor(String nodeId) {
381 if (nodeId == null) {
385 if (!outboundNeighbors.contains(nodeId)) {
386 outboundNeighbors.add(nodeId);
391 public boolean isAtMaxDepth() {
392 return (nodeDepth >= this.visualizationConfigs.getMaxSelfLinkTraversalDepth());
395 public ConcurrentLinkedDeque<String> getInboundNeighbors() {
396 return inboundNeighbors;
399 public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
400 this.inboundNeighbors = inboundNeighbors;
403 public Collection<String> getOutboundNeighbors() {
404 List<String> result = new ArrayList<String>();
406 Iterator<String> neighborIterator = outboundNeighbors.iterator();
408 while (neighborIterator.hasNext()) {
409 result.add(neighborIterator.next());
418 * @param newDepth the new depth
419 * @return true, if successful
421 public boolean changeDepth(int newDepth) {
423 boolean nodeDepthWasChanged = false;
425 if (newDepth < nodeDepth) {
426 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
427 String.valueOf(this.nodeDepth), String.valueOf(newDepth));
428 this.nodeDepth = newDepth;
429 nodeDepthWasChanged = true;
432 return nodeDepthWasChanged;
436 public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
437 this.outboundNeighbors = outboundNeighbors;
440 public boolean isRootNode() {
444 public void setRootNode(boolean isRootNode) {
445 this.isRootNode = isRootNode;
451 * @param newState the new state
452 * @param action the action
454 public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
456 * NodeId may be null depending on the current node life-cycle state
459 if (getNodeId() != null) {
460 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
462 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
464 this.state = newState;
467 public boolean isSelfLinkPendingResolve() {
468 return selfLinkPendingResolve;
471 public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
472 this.selfLinkPendingResolve = selfLinkPendingResolve;
475 public boolean isSelflinkRetrievalFailure() {
476 return selflinkRetrievalFailure;
479 public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
480 this.selflinkRetrievalFailure = selflinkRetrievalFailure;
483 public void setOxmModelLoader(OxmModelLoader loader) {
484 this.oxmModelLoader = loader;
487 public boolean getSelfLinkProcessed() {
488 return selfLinkProcessed.get();
491 public void setSelfLinkProcessed(boolean selfLinkProcessed) {
492 this.selfLinkProcessed.set(selfLinkProcessed);
495 public boolean getNodeIntegrityProcessed() {
496 return nodeIntegrityProcessed.get();
499 public void setNodeIntegrityProcessed(boolean nodeIntegrityProcessed) {
500 this.nodeIntegrityProcessed.set(nodeIntegrityProcessed);
503 public boolean isDirectSelfLink() {
504 return isDirectSelfLink(this.selfLink);
508 * Checks if is direct self link.
510 * @param link the link
511 * @return true, if is direct self link
513 public static boolean isDirectSelfLink(String link) {
519 return link.contains("/resources/id/");
523 public Map<String, String> getProperties() {
528 * Adds the error cause.
530 * @param error the error
532 public void addErrorCause(String error) {
533 if (!errorCauses.contains(error)) {
534 errorCauses.add(error);
542 * @param value the value
544 public void addProperty(String key, String value) {
545 properties.put(key, value);
548 public boolean isProcessingErrorOccurred() {
549 return processingErrorOccurred;
552 public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
553 this.processingErrorOccurred = processingErrorOccurred;
556 public String getNodeId() {
560 public void setNodeId(String nodeId) {
561 this.nodeId = nodeId;
564 public String getEntityType() {
568 public void setEntityType(String entityType) {
569 this.entityType = entityType;
572 public String getSelfLink() {
577 * Calculate edit attribute uri.
579 * @param link the link
582 public String calculateEditAttributeUri(String link) {
584 Pattern pattern = Pattern.compile(URIRegexPattern);
585 Matcher matcher = pattern.matcher(link);
586 if (matcher.find()) {
587 uri = link.substring(matcher.end());
593 * Analyze self link relationship list.
595 * @param jsonResult the json result
596 * @return the relationship list
598 private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
601 RelationshipList relationshipList = null;
604 relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
605 } catch (Exception exc) {
606 LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
609 return relationshipList;
613 * Adds the relationship list.
615 * @param relationshipList the relationship list
617 public void addRelationshipList(RelationshipList relationshipList) {
619 if (!relationshipLists.contains(relationshipList)) {
620 relationshipLists.add(relationshipList);
626 * Process pathed self link response.
628 * @param selfLinkJsonResponse the self link json response
629 * @param startNodeType the start node type
630 * @param startNodeResourceKey the start node resource key
632 public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
633 String startNodeResourceKey) {
635 if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
636 LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
641 JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
643 Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
644 Entry<String, JsonNode> field = null;
646 while (fieldNames.hasNext()) {
648 field = fieldNames.next();
651 * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
652 * flattening code needs to live
655 String fieldName = field.getKey();
657 if ("relationship-list".equals(fieldName)) {
660 * Parse the relationship list like we were doing before, so we can determine whether or
661 * not to keep it or traverse it after we have performed the evaluative node depth logic.
663 RelationshipList relationshipList =
664 analyzeSelfLinkRelationshipList(field.getValue().toString());
666 if (relationshipList != null) {
667 this.relationshipLists.add(relationshipList);
669 LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
672 JsonNode nodeValue = field.getValue();
674 if (nodeValue != null && nodeValue.isValueNode()) {
677 * before we blindly add the fieldName and value to our property set, let's do one more
678 * check to see if the field name is an entity type. If it is, then our complex
679 * attribute processing code will pick it up and process it instead, but this is
680 * probably more likely just for array node types, but we'll see.
683 if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
685 * this is no an entity type as far as we can tell, so we can add it to our property
689 addProperty(fieldName, nodeValue.asText());
695 if (nodeValue.isArray()) {
698 * make sure array entity-type collection is not an entityType before adding it to the
699 * property set. The expetation is that it will be added the visualization through a
700 * complex group or relationship.
703 if (oxmEntityLookup.getEntityDescriptors().get(field.getKey()) == null) {
705 * this is no an entity type as far as we can tell, so we can add it to our property
709 addProperty(field.getKey(), nodeValue.toString());
715 complexGroups.add(nodeValue);
725 } catch (IOException exc) {
726 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
727 this.setProcessingErrorOccurred(true);
729 "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
734 public void setSelfLink(String selfLink) {
735 this.selfLink = selfLink;
739 * Adds the complex group.
741 * @param complexGroup the complex group
743 public void addComplexGroup(JsonNode complexGroup) {
745 if (!complexGroups.contains(complexGroup)) {
746 complexGroups.add(complexGroup);
754 * @param level the level
755 * @param paddingString the padding string
756 * @return the padding
758 private static String getPadding(int level, String paddingString) {
759 StringBuilder sb = new StringBuilder(32);
760 for (int x = 0; x < level; x++) {
761 sb.append(paddingString);
763 return sb.toString();
769 * @param showProperties the show properties
772 public String dumpNodeTree(boolean showProperties) {
773 return dumpNodeTree(0, showProperties);
779 * @param level the level
780 * @param showProperties the show properties
783 private String dumpNodeTree(int level, boolean showProperties) {
784 StringBuilder sb = new StringBuilder(128);
785 String padding = getPadding(level, " ");
787 sb.append(padding + " -> " + getNodeId() + "]").append("\n");
788 sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
789 sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
790 sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
792 if (showProperties) {
793 Set<Entry<String, String>> entries = properties.entrySet();
794 for (Entry<String, String> entry : entries) {
796 padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
801 sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
804 sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
806 for (String inboundNeighbor : inboundNeighbors) {
807 sb.append("\n").append(inboundNeighbor.toString());
810 sb.append(padding + " ----> Outbound Neighbors:").append("\n");
811 sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
813 for (String outboundNeighbor : outboundNeighbors) {
814 sb.append("\n").append(outboundNeighbor.toString());
817 return sb.toString();
821 public String getProcessingErrorCauses() {
823 StringBuilder sb = new StringBuilder(128);
825 for (String c : this.errorCauses) {
826 sb.append(c).append("\n");
829 return sb.toString();