Remove StoreTreeNodes.getChild()
[yangtools.git] / data / yang-data-tree-spi / src / main / java / org / opendaylight / yangtools / yang / data / tree / spi / TerminalDataTreeCandidateNode.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.tree.spi;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
12
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;
22
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;
30
31     TerminalDataTreeCandidateNode(PathArgument identifier, NormalizedNode data,
32                                   TerminalDataTreeCandidateNode parentNode) {
33         this(identifier, data);
34         this.parentNode = requireNonNull(parentNode);
35     }
36
37     TerminalDataTreeCandidateNode(PathArgument identifier, NormalizedNode data) {
38         this(identifier, ModificationType.UNMODIFIED, data, data);
39     }
40
41     TerminalDataTreeCandidateNode(PathArgument identifier, ModificationType modificationType,
42                                   NormalizedNode before, NormalizedNode after) {
43         this.modificationType = modificationType;
44         this.identifier = identifier;
45         this.before = before;
46         this.after = after;
47     }
48
49     @Override
50     public PathArgument getIdentifier() {
51         return identifier;
52     }
53
54     @Override
55     public Collection<DataTreeCandidateNode> getChildNodes() {
56         return Collections.unmodifiableCollection(childNodes.values());
57     }
58
59     @Override
60     public Optional<DataTreeCandidateNode> getModifiedChild(
61             PathArgument childIdentifier) {
62         return Optional.ofNullable(childNodes.get(identifier));
63     }
64
65     @Override
66     public ModificationType getModificationType() {
67         return modificationType;
68     }
69
70     @Override
71     public Optional<NormalizedNode> getDataAfter() {
72         return Optional.ofNullable(after);
73     }
74
75     @NonNull Optional<NormalizedNode> getDataAfter(PathArgument id) {
76         return getNode(id).flatMap(TerminalDataTreeCandidateNode::getDataAfter);
77     }
78
79     @Override
80     public Optional<NormalizedNode> getDataBefore() {
81         return Optional.ofNullable(before);
82     }
83
84     @NonNull Optional<NormalizedNode> getDataBefore(PathArgument id) {
85         Optional<TerminalDataTreeCandidateNode> node = getNode(id);
86         if (node.isPresent()) {
87             return node.get().getDataBefore();
88         }
89         return Optional.empty();
90     }
91
92     void setAfter(NormalizedNode after) {
93         this.after = after;
94     }
95
96     void addChildNode(TerminalDataTreeCandidateNode node) {
97         childNodes.put(node.getIdentifier(), node);
98     }
99
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");
104         }
105         node.get().setModification(modification);
106     }
107
108     private void setModification(ModificationType modification) {
109         this.modificationType = modification;
110     }
111
112     ModificationType getModification(PathArgument id) {
113         Optional<TerminalDataTreeCandidateNode> node = getNode(id);
114         return (node.isEmpty() ? ModificationType.UNMODIFIED : node.get().getModificationType());
115     }
116
117     void deleteNode(PathArgument id) {
118         if (id == null) {
119             modificationType = ModificationType.UNMODIFIED;
120             return;
121         }
122         Optional<TerminalDataTreeCandidateNode> node = getNode(id);
123         if (node.isEmpty()) {
124             throw new IllegalArgumentException("No node with " + id + " id was found");
125         }
126         node.get().parentNode.deleteChild(id);
127     }
128
129     private void deleteChild(PathArgument id) {
130         childNodes.remove(id);
131     }
132
133     @NonNull Optional<TerminalDataTreeCandidateNode> getNode(PathArgument id) {
134         if (id == null) {
135             return Optional.of(this);
136         }
137         if (childNodes.isEmpty()) {
138             return Optional.empty();
139         }
140         if (childNodes.containsKey(id)) {
141             return Optional.ofNullable(childNodes.get(id));
142         }
143         return findNode(id);
144     }
145
146     void setData(PathArgument id, NormalizedNode node) {
147         TerminalDataTreeCandidateNode terminalDataTreeCandidateNode = getNode(id).get();
148         terminalDataTreeCandidateNode.setAfter(node);
149     }
150
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);
155         });
156         return findNode(nodes, id);
157     }
158
159     private @NonNull Optional<TerminalDataTreeCandidateNode> findNode(
160             Collection<HashMap<PathArgument, TerminalDataTreeCandidateNode>> nodes,
161             PathArgument id) {
162         if (nodes.isEmpty()) {
163             return Optional.empty();
164         }
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));
169             }
170             map.forEach((childIdentifier, childNode) -> {
171                 nextNodes.add(childNode.childNodes);
172             });
173         }
174         return findNode(nextNodes, id);
175     }
176 }