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.
26 package org.openecomp.sparky.viewandinspect.entity;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
35 import java.util.Map.Entry;
37 import java.util.concurrent.ConcurrentLinkedDeque;
38 import java.util.concurrent.atomic.AtomicBoolean;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
42 import org.openecomp.cl.api.Logger;
43 import org.openecomp.cl.eelf.LoggerFactory;
44 import org.openecomp.sparky.config.oxm.OxmModelLoader;
45 import org.openecomp.sparky.dal.rest.OperationResult;
46 import org.openecomp.sparky.logging.AaiUiMsgs;
47 import org.openecomp.sparky.viewandinspect.config.VisualizationConfig;
48 import org.openecomp.sparky.viewandinspect.enumeration.NodeProcessingAction;
49 import org.openecomp.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;
71 private List<JsonNode> complexGroups;
72 private List<RelationshipList> relationshipLists;
73 private int nodeDepth;
74 private OperationResult opResult;
77 private boolean processingErrorOccurred;
78 private List<String> errorCauses;
79 private boolean selflinkRetrievalFailure;
80 private NodeProcessingState state;
82 private boolean processedNeighbors;
84 private boolean selfLinkPendingResolve;
87 * I think we shouldn't be using this crutch flags. If these things are meant
88 * to represent the current state of the node, then they should be legitimate
92 private boolean selfLinkDeterminationPending;
94 private AtomicBoolean selfLinkProcessed;
96 private OxmModelLoader oxmModelLoader;
97 private VisualizationConfig visualizationConfig;
99 private String entityType;
100 private String primaryKeyName;
101 private String primaryKeyValue;
103 private boolean nodeIssue;
104 private boolean ignoredByFilter;
106 private boolean resolvedSelfLink;
108 private Map<String, String> properties;
109 private ArrayList<String> queryParams;
111 private ObjectMapper mapper;
114 * Instantiates a new active inventory node.
116 public ActiveInventoryNode() {
121 * Instantiates a new active inventory node.
125 public ActiveInventoryNode(String key) {
127 this.entityType = null;
128 this.selfLink = null;
129 this.properties = new HashMap<String, String>();
130 this.processingErrorOccurred = false;
131 this.errorCauses = new ArrayList<String>();
132 this.selflinkRetrievalFailure = false;
133 this.nodeIssue = false;
134 this.state = NodeProcessingState.INIT;
135 this.selfLinkPendingResolve = false;
136 this.selfLinkDeterminationPending = false;
138 selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
139 oxmModelLoader = null;
140 visualizationConfig = null;
143 inboundNeighbors = new ConcurrentLinkedDeque<String>();
144 outboundNeighbors = 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 addQueryParams(Collection<String> params) {
172 if (params != null & params.size() > 0) {
174 for (String param : params) {
175 addQueryParam(param);
181 public List<String> getQueryParams() {
185 public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
186 this.selfLinkDeterminationPending = selfLinkDeterminationPending;
189 public boolean isSelfLinkDeterminationPending() {
190 return selfLinkDeterminationPending;
193 public NodeProcessingState getState() {
197 public List<JsonNode> getComplexGroups() {
198 return complexGroups;
201 public List<RelationshipList> getRelationshipLists() {
202 return relationshipLists;
205 public OperationResult getOpResult() {
209 public void setOpResult(OperationResult opResult) {
210 this.opResult = opResult;
213 public String getPrimaryKeyName() {
214 return primaryKeyName;
218 * Gets the visualization config.
220 * @return the visualization config
222 public VisualizationConfig getvisualizationConfig() {
223 return visualizationConfig;
226 public int getNodeDepth() {
230 public void setNodeDepth(int nodeDepth) {
231 this.nodeDepth = nodeDepth;
235 * Sets the visualization config.
237 * @param visualizationConfig the new visualization config
239 public void setvisualizationConfig(VisualizationConfig visualizationConfig) {
240 this.visualizationConfig = visualizationConfig;
243 public OxmModelLoader getOxmModelLoader() {
244 return oxmModelLoader;
247 public void setPrimaryKeyName(String primaryKeyName) {
248 this.primaryKeyName = primaryKeyName;
251 public String getPrimaryKeyValue() {
252 return primaryKeyValue;
255 public void setPrimaryKeyValue(String primaryKeyValue) {
256 this.primaryKeyValue = primaryKeyValue;
259 public boolean isNodeIssue() {
263 public boolean isIgnoredByFilter() {
264 return ignoredByFilter;
267 public void setIgnoredByFilter(boolean ignoredByFilter) {
268 this.ignoredByFilter = ignoredByFilter;
271 public void setNodeIssue(boolean nodeIssue) {
272 this.nodeIssue = nodeIssue;
276 * Checks for processed neighbors.
278 * @return true, if successful
280 public boolean hasProcessedNeighbors() {
281 return processedNeighbors;
284 public void setProcessedNeighbors(boolean processedNeighbors) {
285 this.processedNeighbors = processedNeighbors;
289 * Checks for resolved self link.
291 * @return true, if successful
293 public boolean hasResolvedSelfLink() {
294 return resolvedSelfLink;
297 public void setResolvedSelfLink(boolean resolvedSelfLink) {
298 this.resolvedSelfLink = resolvedSelfLink;
302 * Checks for neighbors.
304 * @return true, if successful
306 public boolean hasNeighbors() {
307 return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
311 * Adds the inbound neighbor.
313 * @param nodeId the node id
315 public void addInboundNeighbor(String nodeId) {
317 if (nodeId == null) {
321 if (!inboundNeighbors.contains(nodeId)) {
322 inboundNeighbors.add(nodeId);
328 * Adds the outbound neighbor.
330 * @param nodeId the node id
332 public void addOutboundNeighbor(String nodeId) {
334 if (nodeId == null) {
338 if (!outboundNeighbors.contains(nodeId)) {
339 outboundNeighbors.add(nodeId);
344 public boolean isAtMaxDepth() {
345 return (nodeDepth >= VisualizationConfig.getConfig().getMaxSelfLinkTraversalDepth());
348 public ConcurrentLinkedDeque<String> getInboundNeighbors() {
349 return inboundNeighbors;
352 public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
353 this.inboundNeighbors = inboundNeighbors;
356 public Collection<String> getOutboundNeighbors() {
357 List<String> result = new ArrayList<String>();
359 Iterator<String> neighborIterator = outboundNeighbors.iterator();
361 while (neighborIterator.hasNext()) {
362 result.add(neighborIterator.next());
371 * @param newDepth the new depth
372 * @return true, if successful
374 public boolean changeDepth(int newDepth) {
376 boolean nodeDepthWasChanged = false;
378 if (newDepth < nodeDepth) {
379 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
380 String.valueOf(this.nodeDepth), String.valueOf(newDepth));
381 this.nodeDepth = newDepth;
382 nodeDepthWasChanged = true;
385 return nodeDepthWasChanged;
389 public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
390 this.outboundNeighbors = outboundNeighbors;
393 public boolean isRootNode() {
397 public void setRootNode(boolean isRootNode) {
398 this.isRootNode = isRootNode;
404 * @param newState the new state
405 * @param action the action
407 public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
409 * NodeId may be null depending on the current node life-cycle state
412 if (getNodeId() != null) {
413 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
415 LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
417 this.state = newState;
420 public boolean isSelfLinkPendingResolve() {
421 return selfLinkPendingResolve;
424 public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
425 this.selfLinkPendingResolve = selfLinkPendingResolve;
428 public boolean isSelflinkRetrievalFailure() {
429 return selflinkRetrievalFailure;
432 public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
433 this.selflinkRetrievalFailure = selflinkRetrievalFailure;
436 public void setOxmModelLoader(OxmModelLoader loader) {
437 this.oxmModelLoader = loader;
440 public boolean getSelfLinkProcessed() {
441 return selfLinkProcessed.get();
444 public void setSelfLinkProcessed(boolean selfLinkProcessed) {
445 this.selfLinkProcessed.set(selfLinkProcessed);
448 public boolean isDirectSelfLink() {
449 // https://aai-int1.test.att.com:8443/aai/v8/resources/id/2458124400
450 return isDirectSelfLink(this.selfLink);
454 * Checks if is direct self link.
456 * @param link the link
457 * @return true, if is direct self link
459 public static boolean isDirectSelfLink(String link) {
460 // https://aai-int1.test.att.com:8443/aai/v8/resources/id/2458124400
466 return link.contains("/resources/id/");
470 public Map<String, String> getProperties() {
475 * Adds the error cause.
477 * @param error the error
479 public void addErrorCause(String error) {
480 if (!errorCauses.contains(error)) {
481 errorCauses.add(error);
489 * @param value the value
491 public void addProperty(String key, String value) {
492 properties.put(key, value);
495 public boolean isProcessingErrorOccurred() {
496 return processingErrorOccurred;
499 public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
500 this.processingErrorOccurred = processingErrorOccurred;
503 public String getNodeId() {
507 public void setNodeId(String nodeId) {
508 this.nodeId = nodeId;
511 public String getEntityType() {
515 public void setEntityType(String entityType) {
516 this.entityType = entityType;
519 public String getSelfLink() {
524 * Calculate edit attribute uri.
526 * @param link the link
529 public String calculateEditAttributeUri(String link) {
531 Pattern pattern = Pattern.compile(URIRegexPattern);
532 Matcher matcher = pattern.matcher(link);
533 if (matcher.find()) {
534 uri = link.substring(matcher.end());
540 * Analyze self link relationship list.
542 * @param jsonResult the json result
543 * @return the relationship list
545 private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
548 RelationshipList relationshipList = null;
551 relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
552 } catch (Exception exc) {
553 LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
556 return relationshipList;
560 * Adds the relationship list.
562 * @param relationshipList the relationship list
564 public void addRelationshipList(RelationshipList relationshipList) {
566 if (!relationshipLists.contains(relationshipList)) {
567 relationshipLists.add(relationshipList);
573 * Process pathed self link response.
575 * @param selfLinkJsonResponse the self link json response
576 * @param startNodeType the start node type
577 * @param startNodeResourceKey the start node resource key
579 public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
580 String startNodeResourceKey) {
582 if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
583 LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
588 JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
590 Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
591 Entry<String, JsonNode> field = null;
593 while (fieldNames.hasNext()) {
595 field = fieldNames.next();
598 * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
599 * flattening code needs to live
602 String fieldName = field.getKey();
604 if ("relationship-list".equals(fieldName)) {
607 * Parse the relationship list like we were doing before, so we can determine whether or
608 * not to keep it or traverse it after we have performed the evaluative node depth logic.
610 RelationshipList relationshipList =
611 analyzeSelfLinkRelationshipList(field.getValue().toString());
613 if (relationshipList != null) {
614 this.relationshipLists.add(relationshipList);
616 LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
619 JsonNode nodeValue = field.getValue();
621 if (nodeValue != null && nodeValue.isValueNode()) {
624 * before we blindly add the fieldName and value to our property set, let's do one more
625 * check to see if the field name is an entity type. If it is, then our complex
626 * attribute processing code will pick it up and process it instead, but this is
627 * probably more likely just for array node types, but we'll see.
630 if (oxmModelLoader.getEntityDescriptor(fieldName) == null) {
632 * this is no an entity type as far as we can tell, so we can add it to our property
636 addProperty(fieldName, nodeValue.asText());
642 if (nodeValue.isArray()) {
645 * make sure array entity-type collection is not an entityType before adding it to the
646 * property set. The expetation is that it will be added the visualization through a
647 * complex group or relationship.
650 if (oxmModelLoader.getEntityDescriptor(field.getKey()) == null) {
652 * this is no an entity type as far as we can tell, so we can add it to our property
656 addProperty(field.getKey(), nodeValue.toString());
662 complexGroups.add(nodeValue);
672 } catch (IOException exc) {
673 LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
674 this.setProcessingErrorOccurred(true);
676 "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
681 public void setSelfLink(String selfLink) {
682 this.selfLink = selfLink;
686 * Adds the complex group.
688 * @param complexGroup the complex group
690 public void addComplexGroup(JsonNode complexGroup) {
692 if (!complexGroups.contains(complexGroup)) {
693 complexGroups.add(complexGroup);
701 * @param level the level
702 * @param paddingString the padding string
703 * @return the padding
705 private static String getPadding(int level, String paddingString) {
706 StringBuilder sb = new StringBuilder(32);
707 for (int x = 0; x < level; x++) {
708 sb.append(paddingString);
710 return sb.toString();
716 * @param showProperties the show properties
719 public String dumpNodeTree(boolean showProperties) {
720 return dumpNodeTree(0, showProperties);
726 * @param level the level
727 * @param showProperties the show properties
730 private String dumpNodeTree(int level, boolean showProperties) {
731 StringBuilder sb = new StringBuilder(128);
732 String padding = getPadding(level, " ");
734 sb.append(padding + " -> " + getNodeId() + "]").append("\n");
735 sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
736 sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
737 sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
739 if (showProperties) {
740 Set<Entry<String, String>> entries = properties.entrySet();
741 for (Entry<String, String> entry : entries) {
743 padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
748 sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
751 sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
753 for (String inboundNeighbor : inboundNeighbors) {
754 sb.append("\n").append(inboundNeighbor.toString());
757 sb.append(padding + " ----> Outbound Neighbors:").append("\n");
758 sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
760 for (String outboundNeighbor : outboundNeighbors) {
761 sb.append("\n").append(outboundNeighbor.toString());
764 return sb.toString();
768 public String getProcessingErrorCauses() {
770 StringBuilder sb = new StringBuilder(128);
772 for (String c : this.errorCauses) {
773 sb.append(c).append("\n");
776 return sb.toString();