Move netconf-dom-api
[netconf.git] / netconf / netconf-util / src / main / java / org / opendaylight / netconf / util / PathNode.java
1 /*
2  * Copyright © 2020 FRINX s.r.o. All rights reserved.
3  * Copyright © 2021 PANTHEON.tech, s.r.o.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.netconf.util;
10
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.Maps;
14 import java.util.Collection;
15 import java.util.LinkedHashMap;
16 import java.util.Map;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.opendaylight.yangtools.concepts.Mutable;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20
21 /**
22  * Representation of the tree node with possible multiple child nodes. Child nodes are identified uniquely by path
23  * argument.
24  */
25 @NonNullByDefault
26 final class PathNode implements Mutable {
27     private final PathArgument argument;
28
29     private Map<PathArgument, PathNode> children;
30
31     private PathNode(final PathArgument argument, final LinkedHashMap<PathArgument, PathNode> children) {
32         this.argument = requireNonNull(argument);
33         this.children = requireNonNull(children);
34     }
35
36     /**
37      * Creation of tree node using a path argument.
38      *
39      * @param argument Path argument
40      */
41     PathNode(final PathArgument argument) {
42         this.argument = requireNonNull(argument);
43         this.children = Map.of();
44     }
45
46     /**
47      * Get path argument.
48      *
49      * @return path argument
50      */
51     PathArgument element() {
52         return argument;
53     }
54
55     /**
56      * Return current child nodes.
57      *
58      * @return Current child nodes
59      */
60     Collection<PathNode> children() {
61         return children.values();
62     }
63
64     /**
65      * Return {@code true} if this node has no child nodes.
66      *
67      * @return {@code true} if this node has no child nodes
68      */
69     boolean isEmpty() {
70         return children.isEmpty();
71     }
72
73     /**
74      * Create a copy of this node with specified immediate child nodes appended.
75      *
76      * @param childArguments Child arguments
77      * @return A copy of this {@link PathNode}
78      * @throws NullPointerException if {@code childArguments} is, or contains, {@code null}
79      */
80     PathNode copyWith(final Collection<PathArgument> childArguments) {
81         final LinkedHashMap<PathArgument, PathNode> copy = children instanceof LinkedHashMap
82             ? new LinkedHashMap<>(children) : Maps.newLinkedHashMapWithExpectedSize(childArguments.size());
83         for (PathArgument childArgument : childArguments) {
84             ensureChild(copy, childArgument);
85         }
86         return new PathNode(argument, copy);
87     }
88
89     /**
90      * Ensure a node for specified argument exists.
91      *
92      * @param childArgument Child argument
93      * @return A child {@link PathNode}
94      * @throws NullPointerException if {@code childArgument} is null
95      */
96     PathNode ensureChild(final PathArgument childArgument) {
97         return ensureChild(mutableChildren(), childArgument);
98     }
99
100     private static PathNode ensureChild(final LinkedHashMap<PathArgument, PathNode> children,
101             final PathArgument childArgument) {
102         return children.computeIfAbsent(requireNonNull(childArgument), PathNode::new);
103     }
104
105     private LinkedHashMap<PathArgument, PathNode> mutableChildren() {
106         final Map<PathArgument, PathNode> local = children;
107         if (local instanceof LinkedHashMap) {
108             return (LinkedHashMap<PathArgument, PathNode>) local;
109         }
110
111         // TODO: LinkedHashMap is rather heavy, do we need to retain insertion order?
112         final LinkedHashMap<PathArgument, PathNode> ret = new LinkedHashMap<>(4);
113         children = ret;
114         return ret;
115     }
116 }