2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.tree.spi;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Optional;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
20 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
21 import org.opendaylight.yangtools.yang.data.tree.api.ModificationType;
23 class TerminalDataTreeCandidateNode implements DataTreeCandidateNode {
24 private ModificationType modificationType;
25 private final PathArgument identifier;
26 private final NormalizedNode before;
27 private NormalizedNode after;
28 private final HashMap<PathArgument, TerminalDataTreeCandidateNode> childNodes = new HashMap<>();
29 private TerminalDataTreeCandidateNode parentNode;
31 TerminalDataTreeCandidateNode(PathArgument identifier, NormalizedNode data,
32 TerminalDataTreeCandidateNode parentNode) {
33 this(identifier, data);
34 this.parentNode = requireNonNull(parentNode);
37 TerminalDataTreeCandidateNode(PathArgument identifier, NormalizedNode data) {
38 this(identifier, ModificationType.UNMODIFIED, data, data);
41 TerminalDataTreeCandidateNode(PathArgument identifier, ModificationType modificationType,
42 NormalizedNode before, NormalizedNode after) {
43 this.modificationType = modificationType;
44 this.identifier = identifier;
50 public PathArgument getIdentifier() {
55 public Collection<DataTreeCandidateNode> getChildNodes() {
56 return Collections.unmodifiableCollection(childNodes.values());
60 public Optional<DataTreeCandidateNode> getModifiedChild(
61 PathArgument childIdentifier) {
62 return Optional.ofNullable(childNodes.get(identifier));
66 public ModificationType getModificationType() {
67 return modificationType;
71 public Optional<NormalizedNode> getDataAfter() {
72 return Optional.ofNullable(after);
75 @NonNull Optional<NormalizedNode> getDataAfter(PathArgument id) {
76 return getNode(id).flatMap(TerminalDataTreeCandidateNode::getDataAfter);
80 public Optional<NormalizedNode> getDataBefore() {
81 return Optional.ofNullable(before);
84 @NonNull Optional<NormalizedNode> getDataBefore(PathArgument id) {
85 Optional<TerminalDataTreeCandidateNode> node = getNode(id);
86 if (node.isPresent()) {
87 return node.get().getDataBefore();
89 return Optional.empty();
92 void setAfter(NormalizedNode after) {
96 void addChildNode(TerminalDataTreeCandidateNode node) {
97 childNodes.put(node.getIdentifier(), node);
100 void setModification(PathArgument id, ModificationType modification) {
101 Optional<TerminalDataTreeCandidateNode> node = getNode(id);
102 if (node.isEmpty()) {
103 throw new IllegalArgumentException("No node with " + id + " id was found");
105 node.get().setModification(modification);
108 private void setModification(ModificationType modification) {
109 this.modificationType = modification;
112 ModificationType getModification(PathArgument id) {
113 Optional<TerminalDataTreeCandidateNode> node = getNode(id);
114 return (node.isEmpty() ? ModificationType.UNMODIFIED : node.get().getModificationType());
117 void deleteNode(PathArgument id) {
119 modificationType = ModificationType.UNMODIFIED;
122 Optional<TerminalDataTreeCandidateNode> node = getNode(id);
123 if (node.isEmpty()) {
124 throw new IllegalArgumentException("No node with " + id + " id was found");
126 node.get().parentNode.deleteChild(id);
129 private void deleteChild(PathArgument id) {
130 childNodes.remove(id);
133 @NonNull Optional<TerminalDataTreeCandidateNode> getNode(PathArgument id) {
135 return Optional.of(this);
137 if (childNodes.isEmpty()) {
138 return Optional.empty();
140 if (childNodes.containsKey(id)) {
141 return Optional.ofNullable(childNodes.get(id));
146 void setData(PathArgument id, NormalizedNode node) {
147 TerminalDataTreeCandidateNode terminalDataTreeCandidateNode = getNode(id).get();
148 terminalDataTreeCandidateNode.setAfter(node);
151 private @NonNull Optional<TerminalDataTreeCandidateNode> findNode(PathArgument id) {
152 Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nodes = new HashSet<>();
153 childNodes.forEach((childIdentifier, childNode) -> {
154 nodes.add(childNode.childNodes);
156 return findNode(nodes, id);
159 private @NonNull Optional<TerminalDataTreeCandidateNode> findNode(
160 Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nodes,
162 if (nodes.isEmpty()) {
163 return Optional.empty();
165 Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nextNodes = new HashSet<>();
166 for (HashMap<PathArgument, TerminalDataTreeCandidateNode> map : nodes) {
167 if (map.containsKey(id)) {
168 return Optional.ofNullable(map.get(id));
170 map.forEach((childIdentifier, childNode) -> {
171 nextNodes.add(childNode.childNodes);
174 return findNode(nextNodes, id);