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;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
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 // Non-final for mocking
24 class TerminalDataTreeCandidateNode implements DataTreeCandidateNode {
25 private ModificationType modificationType;
26 private final PathArgument identifier;
27 private final NormalizedNode before;
28 private NormalizedNode after;
29 private final HashMap<PathArgument, TerminalDataTreeCandidateNode> childNodes = new HashMap<>();
30 private TerminalDataTreeCandidateNode parentNode;
32 TerminalDataTreeCandidateNode(final PathArgument identifier, final NormalizedNode data,
33 final TerminalDataTreeCandidateNode parentNode) {
34 this(identifier, data);
35 this.parentNode = requireNonNull(parentNode);
38 TerminalDataTreeCandidateNode(final PathArgument identifier, final NormalizedNode data) {
39 this(identifier, ModificationType.UNMODIFIED, data, data);
42 TerminalDataTreeCandidateNode(final PathArgument identifier, final ModificationType modificationType,
43 final NormalizedNode before, final NormalizedNode after) {
44 this.modificationType = modificationType;
45 this.identifier = identifier;
51 public PathArgument getIdentifier() {
56 public Collection<DataTreeCandidateNode> getChildNodes() {
57 return Collections.unmodifiableCollection(childNodes.values());
61 public Optional<DataTreeCandidateNode> getModifiedChild(final 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(final PathArgument id) {
76 return getNode(id).flatMap(TerminalDataTreeCandidateNode::getDataAfter);
80 public Optional<NormalizedNode> getDataBefore() {
81 return Optional.ofNullable(before);
84 @NonNull Optional<NormalizedNode> getDataBefore(final PathArgument id) {
85 return getNode(id).flatMap(TerminalDataTreeCandidateNode::getDataBefore);
88 void setAfter(final NormalizedNode after) {
92 void addChildNode(final TerminalDataTreeCandidateNode node) {
93 childNodes.put(node.getIdentifier(), node);
96 void setModification(final PathArgument id, final ModificationType modification) {
98 .orElseThrow(() -> new IllegalArgumentException("No node with " + id + " id was found"))
99 .setModification(modification);
102 private void setModification(final ModificationType modification) {
103 modificationType = modification;
106 ModificationType getModification(final PathArgument id) {
107 return getNode(id).map(TerminalDataTreeCandidateNode::getModificationType).orElse(ModificationType.UNMODIFIED);
110 void deleteNode(final PathArgument id) {
112 getNode(id).orElseThrow(() -> new IllegalArgumentException("No node with " + id + " id was found"))
113 .parentNode.deleteChild(id);
115 modificationType = ModificationType.UNMODIFIED;
119 private void deleteChild(final PathArgument id) {
120 childNodes.remove(id);
123 @NonNull Optional<TerminalDataTreeCandidateNode> getNode(final PathArgument id) {
125 return Optional.of(this);
127 if (childNodes.isEmpty()) {
128 return Optional.empty();
130 if (childNodes.containsKey(id)) {
131 return Optional.ofNullable(childNodes.get(id));
136 void setData(final PathArgument id, final NormalizedNode node) {
137 getNode(id).orElseThrow().setAfter(node);
140 private @NonNull Optional<TerminalDataTreeCandidateNode> findNode(final PathArgument id) {
141 Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nodes = new HashSet<>();
142 childNodes.forEach((childIdentifier, childNode) -> {
143 nodes.add(childNode.childNodes);
145 return findNode(nodes, id);
148 private @NonNull Optional<TerminalDataTreeCandidateNode> findNode(
149 final Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nodes, final PathArgument id) {
150 if (nodes.isEmpty()) {
151 return Optional.empty();
153 Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nextNodes = new HashSet<>();
154 for (HashMap<PathArgument, TerminalDataTreeCandidateNode> map : nodes) {
155 if (map.containsKey(id)) {
156 return Optional.ofNullable(map.get(id));
158 map.forEach((childIdentifier, childNode) -> {
159 nextNodes.add(childNode.childNodes);
162 return findNode(nextNodes, id);