Madan Jampani

Updates to DocumentTreeNode + Simple implementation of DocumentTree interface

Change-Id: Icc162201a50de8ae48abdb8e769fb6ed86138a03
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 16
17 package org.onosproject.store.service; 17 package org.onosproject.store.service;
18 18
19 +import java.util.Arrays;
19 import java.util.Iterator; 20 import java.util.Iterator;
20 import java.util.List; 21 import java.util.List;
21 import java.util.Objects; 22 import java.util.Objects;
...@@ -71,6 +72,16 @@ public class DocumentPath implements Comparable<DocumentPath> { ...@@ -71,6 +72,16 @@ public class DocumentPath implements Comparable<DocumentPath> {
71 } 72 }
72 73
73 /** 74 /**
75 + * Creates a new {@code DocumentPath} from a period delimited path string.
76 + *
77 + * @param path path string
78 + * @return {@code DocumentPath} instance
79 + */
80 + public static DocumentPath from(String path) {
81 + return new DocumentPath(Arrays.asList(path.split("\\.")));
82 + }
83 +
84 + /**
74 * Returns a path for the parent of this node. 85 * Returns a path for the parent of this node.
75 * 86 *
76 * @return parent node path. If this path is for the root, returns {@code null}. 87 * @return parent node path. If this path is for the root, returns {@code null}.
......
...@@ -16,15 +16,16 @@ ...@@ -16,15 +16,16 @@
16 16
17 package org.onosproject.store.service; 17 package org.onosproject.store.service;
18 18
19 -import java.util.Iterator; 19 +import java.util.Map;
20 20
21 -import org.onosproject.store.primitives.DocumentTreeNode; 21 +import javax.annotation.concurrent.NotThreadSafe;
22 22
23 /** 23 /**
24 * A hierarchical <a href="https://en.wikipedia.org/wiki/Document_Object_Model">document tree</a> data structure. 24 * A hierarchical <a href="https://en.wikipedia.org/wiki/Document_Object_Model">document tree</a> data structure.
25 * 25 *
26 * @param <V> document tree value type 26 * @param <V> document tree value type
27 */ 27 */
28 +@NotThreadSafe
28 public interface DocumentTree<V> { 29 public interface DocumentTree<V> {
29 30
30 /** 31 /**
...@@ -35,13 +36,13 @@ public interface DocumentTree<V> { ...@@ -35,13 +36,13 @@ public interface DocumentTree<V> {
35 DocumentPath root(); 36 DocumentPath root();
36 37
37 /** 38 /**
38 - * Returns an iterator for all the first order descendants of a node. 39 + * Returns the child values for this node.
39 * 40 *
40 * @param path path to the node 41 * @param path path to the node
41 - * @return an iterator for the child nodes of the specified node path 42 + * @return mapping from a child name to its value
42 * @throws NoSuchDocumentPathException if the path does not point to a valid node 43 * @throws NoSuchDocumentPathException if the path does not point to a valid node
43 */ 44 */
44 - Iterator<DocumentTreeNode<V>> getChildren(DocumentPath path); 45 + Map<String, Versioned<V>> getChildren(DocumentPath path);
45 46
46 /** 47 /**
47 * Returns a document tree node. 48 * Returns a document tree node.
...@@ -49,7 +50,7 @@ public interface DocumentTree<V> { ...@@ -49,7 +50,7 @@ public interface DocumentTree<V> {
49 * @param path path to node 50 * @param path path to node
50 * @return node value or {@code null} if path does not point to a valid node 51 * @return node value or {@code null} if path does not point to a valid node
51 */ 52 */
52 - DocumentTreeNode<V> getNode(DocumentPath path); 53 + Versioned<V> get(DocumentPath path);
53 54
54 /** 55 /**
55 * Creates or updates a document tree node. 56 * Creates or updates a document tree node.
...@@ -59,7 +60,7 @@ public interface DocumentTree<V> { ...@@ -59,7 +60,7 @@ public interface DocumentTree<V> {
59 * @return the previous mapping or {@code null} if there was no previous mapping 60 * @return the previous mapping or {@code null} if there was no previous mapping
60 * @throws NoSuchDocumentPathException if the parent node (for the node to create/update) does not exist 61 * @throws NoSuchDocumentPathException if the parent node (for the node to create/update) does not exist
61 */ 62 */
62 - V putNode(DocumentPath path, V value); 63 + Versioned<V> set(DocumentPath path, V value);
63 64
64 /** 65 /**
65 * Creates a document tree node if one does not exist already. 66 * Creates a document tree node if one does not exist already.
...@@ -69,7 +70,7 @@ public interface DocumentTree<V> { ...@@ -69,7 +70,7 @@ public interface DocumentTree<V> {
69 * @return returns {@code true} if the mapping could be added successfully, {@code false} otherwise 70 * @return returns {@code true} if the mapping could be added successfully, {@code false} otherwise
70 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist 71 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist
71 */ 72 */
72 - boolean createNode(DocumentPath path, V value); 73 + boolean create(DocumentPath path, V value);
73 74
74 /** 75 /**
75 * Conditionally updates a tree node if the current version matches a specified version. 76 * Conditionally updates a tree node if the current version matches a specified version.
...@@ -77,7 +78,7 @@ public interface DocumentTree<V> { ...@@ -77,7 +78,7 @@ public interface DocumentTree<V> {
77 * @param path path for the node to create 78 * @param path path for the node to create
78 * @param newValue the non-null value to be associated with the key 79 * @param newValue the non-null value to be associated with the key
79 * @param version current version of the value for update to occur 80 * @param version current version of the value for update to occur
80 - * @return returns {@code true} if the update was made, {@code false} otherwise 81 + * @return returns {@code true} if the update was made and the tree was modified, {@code false} otherwise
81 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist 82 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist
82 */ 83 */
83 boolean replace(DocumentPath path, V newValue, long version); 84 boolean replace(DocumentPath path, V newValue, long version);
...@@ -88,7 +89,8 @@ public interface DocumentTree<V> { ...@@ -88,7 +89,8 @@ public interface DocumentTree<V> {
88 * @param path path for the node to create 89 * @param path path for the node to create
89 * @param newValue the non-null value to be associated with the key 90 * @param newValue the non-null value to be associated with the key
90 * @param currentValue current value for update to occur 91 * @param currentValue current value for update to occur
91 - * @return returns {@code true} if the update was made, {@code false} otherwise 92 + * @return returns {@code true} if the update was made and the tree was modified, {@code false} otherwise.
93 + * This method returns {@code false} if the newValue and currentValue are same.
92 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist 94 * @throws NoSuchDocumentPathException if the parent node (for the node to create) does not exist
93 */ 95 */
94 boolean replace(DocumentPath path, V newValue, V currentValue); 96 boolean replace(DocumentPath path, V newValue, V currentValue);
...@@ -96,12 +98,11 @@ public interface DocumentTree<V> { ...@@ -96,12 +98,11 @@ public interface DocumentTree<V> {
96 /** 98 /**
97 * Removes the node with the specified path. 99 * Removes the node with the specified path.
98 * 100 *
99 - * is not a leaf node i.e has one or more children 101 + * @param path path for the node to remove
100 - * @param key path for the node to remove
101 * @return the previous value of the node or {@code null} if it did not exist 102 * @return the previous value of the node or {@code null} if it did not exist
102 * @throws IllegalDocumentModificationException if the remove to be removed 103 * @throws IllegalDocumentModificationException if the remove to be removed
103 */ 104 */
104 - V removeNode(DocumentPath key); 105 + Versioned<V> removeNode(DocumentPath path);
105 106
106 /** 107 /**
107 * Registers a listener to be notified when a subtree rooted at the specified path 108 * Registers a listener to be notified when a subtree rooted at the specified path
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +import java.util.Iterator;
20 +
21 +import javax.annotation.concurrent.NotThreadSafe;
22 +
23 +/**
24 + * A {@code DocumentTree} node.
25 + *
26 + * @param <V> value type
27 + */
28 +@NotThreadSafe
29 +public interface DocumentTreeNode<V> {
30 +
31 + /**
32 + * Returns the path to this node in a {@code DocumentTree}.
33 + *
34 + * @return absolute path
35 + */
36 + DocumentPath path();
37 +
38 + /**
39 + * Returns the value of this node.
40 + *
41 + * @return node value (and version)
42 + */
43 + Versioned<V> value();
44 +
45 + /**
46 + * Returns the children of this node.
47 + *
48 + * @return iterator for this node's children
49 + */
50 + Iterator<DocumentTreeNode<V>> children();
51 +
52 + /**
53 + * Returns the child node of this node with the specified relative path name.
54 + *
55 + * @param relativePath relative path name for the child node.
56 + * @return child node; this method returns {@code null} if no such child exists
57 + */
58 + DocumentTreeNode<V> child(String relativePath);
59 +
60 + /**
61 + * Returns if this node has one or more children.
62 + * @return {@code true} if yes, {@code false} otherwise
63 + */
64 + default boolean hasChildren() {
65 + return children().hasNext();
66 + }
67 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.primitives.resources.impl;
18 +
19 +import java.util.Iterator;
20 +import java.util.Map;
21 +import java.util.Objects;
22 +import java.util.concurrent.atomic.AtomicInteger;
23 +
24 +import org.onosproject.store.service.DocumentPath;
25 +import org.onosproject.store.service.DocumentTree;
26 +import org.onosproject.store.service.DocumentTreeListener;
27 +import org.onosproject.store.service.DocumentTreeNode;
28 +import org.onosproject.store.service.IllegalDocumentModificationException;
29 +import org.onosproject.store.service.NoSuchDocumentPathException;
30 +import org.onosproject.store.service.Versioned;
31 +
32 +import com.google.common.base.Preconditions;
33 +import com.google.common.collect.Maps;
34 +
35 +/**
36 + * Simple implementation of a {@link DocumentTree}.
37 + *
38 + * @param <V> tree node value type
39 + */
40 +public class DefaultDocumentTree<V> implements DocumentTree<V> {
41 +
42 + private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
43 + private final DefaultDocumentTreeNode<V> root;
44 + private final AtomicInteger versionCounter = new AtomicInteger(0);
45 +
46 + public DefaultDocumentTree() {
47 + root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, nextVersion(), null);
48 + }
49 +
50 + @Override
51 + public DocumentPath root() {
52 + return ROOT_PATH;
53 + }
54 +
55 + @Override
56 + public Map<String, Versioned<V>> getChildren(DocumentPath path) {
57 + DocumentTreeNode<V> node = getNode(path);
58 + if (node != null) {
59 + Map<String, Versioned<V>> childrenValues = Maps.newHashMap();
60 + node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
61 + return childrenValues;
62 + }
63 + throw new NoSuchDocumentPathException();
64 + }
65 +
66 + @Override
67 + public Versioned<V> get(DocumentPath path) {
68 + DocumentTreeNode<V> currentNode = getNode(path);
69 + return currentNode != null ? currentNode.value() : null;
70 + }
71 +
72 + @Override
73 + public Versioned<V> set(DocumentPath path, V value) {
74 + checkRootModification(path);
75 + DefaultDocumentTreeNode<V> node = getNode(path);
76 + if (node != null) {
77 + return node.update(value, nextVersion());
78 + } else {
79 + create(path, value);
80 + return null;
81 + }
82 + }
83 +
84 + @Override
85 + public boolean create(DocumentPath path, V value) {
86 + checkRootModification(path);
87 + DocumentTreeNode<V> node = getNode(path);
88 + if (node != null) {
89 + return false;
90 + }
91 + DocumentPath parentPath = path.parent();
92 + DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
93 + if (parentNode == null) {
94 + throw new IllegalDocumentModificationException();
95 + }
96 + parentNode.addChild(simpleName(path), value, nextVersion());
97 + return true;
98 + }
99 +
100 + @Override
101 + public boolean replace(DocumentPath path, V newValue, long version) {
102 + checkRootModification(path);
103 + DocumentTreeNode<V> node = getNode(path);
104 + if (node != null && node.value() != null && node.value().version() == version) {
105 + if (!Objects.equals(newValue, node.value().value())) {
106 + set(path, newValue);
107 + return true;
108 + }
109 + }
110 + return false;
111 + }
112 +
113 + @Override
114 + public boolean replace(DocumentPath path, V newValue, V currentValue) {
115 + checkRootModification(path);
116 + if (Objects.equals(newValue, currentValue)) {
117 + return false;
118 + }
119 + DocumentTreeNode<V> node = getNode(path);
120 + if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
121 + set(path, newValue);
122 + return true;
123 + }
124 + return false;
125 + }
126 +
127 + @Override
128 + public Versioned<V> removeNode(DocumentPath path) {
129 + checkRootModification(path);
130 + DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
131 + if (nodeToRemove == null) {
132 + throw new NoSuchDocumentPathException();
133 + }
134 + if (nodeToRemove.hasChildren()) {
135 + throw new IllegalDocumentModificationException();
136 + }
137 + DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
138 + parent.removeChild(simpleName(path));
139 + return nodeToRemove.value();
140 + }
141 +
142 + @Override
143 + public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
144 + // TODO Auto-generated method stub
145 + }
146 +
147 + @Override
148 + public void removeListener(DocumentTreeListener<V> listener) {
149 + // TODO Auto-generated method stub
150 + }
151 +
152 + private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
153 + Iterator<String> pathElements = path.pathElements().iterator();
154 + DefaultDocumentTreeNode<V> currentNode = root;
155 + Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
156 + while (pathElements.hasNext() && currentNode != null) {
157 + currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
158 + }
159 + return currentNode;
160 + }
161 +
162 + private long nextVersion() {
163 + return versionCounter.incrementAndGet();
164 + }
165 +
166 + private String simpleName(DocumentPath path) {
167 + return path.pathElements().get(path.pathElements().size() - 1);
168 + }
169 +
170 + private void checkRootModification(DocumentPath path) {
171 + if (ROOT_PATH.equals(path)) {
172 + throw new IllegalDocumentModificationException();
173 + }
174 + }
175 +}
...@@ -14,121 +14,105 @@ ...@@ -14,121 +14,105 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.onosproject.store.primitives; 17 +package org.onosproject.store.primitives.resources.impl;
18 18
19 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkNotNull;
20 20
21 -import java.util.Comparator;
22 import java.util.Iterator; 21 import java.util.Iterator;
23 import java.util.Objects; 22 import java.util.Objects;
24 -import java.util.TreeSet; 23 +import java.util.TreeMap;
25 24
26 import org.onosproject.store.service.DocumentPath; 25 import org.onosproject.store.service.DocumentPath;
26 +import org.onosproject.store.service.DocumentTreeNode;
27 +import org.onosproject.store.service.Versioned;
27 28
28 import com.google.common.base.MoreObjects; 29 import com.google.common.base.MoreObjects;
30 +import com.google.common.collect.ImmutableList;
31 +import com.google.common.collect.Maps;
29 import com.google.common.collect.Sets; 32 import com.google.common.collect.Sets;
30 33
31 /** 34 /**
32 * A {@code DocumentTree} node. 35 * A {@code DocumentTree} node.
33 */ 36 */
34 -public class DocumentTreeNode<V> { 37 +public class DefaultDocumentTreeNode<V> implements DocumentTreeNode<V> {
35 private final DocumentPath key; 38 private final DocumentPath key;
36 - private V value; 39 + private Versioned<V> value;
37 - private long version; 40 + private final TreeMap<String, DocumentTreeNode<V>> children = Maps.newTreeMap();
38 - private final TreeSet<DocumentTreeNode<V>> children =
39 - Sets.newTreeSet(new Comparator<DocumentTreeNode<V>>() {
40 - @Override
41 - public int compare(DocumentTreeNode<V> o1,
42 - DocumentTreeNode<V> o2) {
43 - return o1.getKey().compareTo(o2.getKey());
44 - }
45 - });
46 private final DocumentTreeNode<V> parent; 41 private final DocumentTreeNode<V> parent;
47 42
48 - public DocumentTreeNode(DocumentPath key, 43 + public DefaultDocumentTreeNode(DocumentPath key,
49 V value, 44 V value,
50 long version, 45 long version,
51 DocumentTreeNode<V> parent) { 46 DocumentTreeNode<V> parent) {
52 this.key = checkNotNull(key); 47 this.key = checkNotNull(key);
53 - this.value = checkNotNull(value); 48 + this.value = new Versioned<>(value, version);
54 - this.version = version;
55 this.parent = parent; 49 this.parent = parent;
56 } 50 }
57 51
58 - /** 52 + @Override
59 - * Returns this node's key. 53 + public DocumentPath path() {
60 - *
61 - * @return the key
62 - */
63 - public DocumentPath getKey() {
64 return key; 54 return key;
65 } 55 }
66 56
67 - /** 57 + @Override
68 - * Returns this node's value. 58 + public Versioned<V> value() {
69 - *
70 - * @return the value
71 - */
72 - public V getValue() {
73 return value; 59 return value;
74 } 60 }
75 61
76 - /** 62 + @Override
77 - * Returns this node's version. 63 + public Iterator<DocumentTreeNode<V>> children() {
78 - * 64 + return ImmutableList.copyOf(children.values()).iterator();
79 - * @return the version
80 - */
81 - public long getVersion() {
82 - return version;
83 } 65 }
84 66
85 - /** 67 + @Override
86 - * Updates this node. 68 + public DocumentTreeNode<V> child(String name) {
87 - * 69 + return children.get(name);
88 - * @param newValue new value to be set
89 - * @param newVersion new version to be set
90 - */
91 - public void update(V newValue, long newVersion) {
92 - this.value = newValue;
93 - this.version = newVersion;
94 } 70 }
95 71
96 - /** 72 +
97 - * Returns a collection of the children of this node. 73 + public DocumentTreeNode<V> parent() {
98 - * 74 + return parent;
99 - * @return iterator for the children of this node.
100 - */
101 - public Iterator<DocumentTreeNode<V>> getChildren() {
102 - return children.iterator();
103 } 75 }
104 76
105 /** 77 /**
106 - * Adds a child to this node. 78 + * Adds a new child only if one does not exist with the name.
107 - * 79 + * @param name relative path name of the child node
108 - * @param child the child node to be added 80 + * @param newValue new value to set
109 - * @return {@code true} if the child set was modified as a result of this call, {@code false} otherwise 81 + * @param newVersion new version to set
82 + * @return previous value; can be {@code null} if no child currently exists with that relative path name.
83 + * a non null return value indicates child already exists and no modification occured.
110 */ 84 */
111 - public boolean addChild(DocumentTreeNode<V> child) { 85 + public Versioned<V> addChild(String name, V newValue, long newVersion) {
112 - return children.add(child); 86 + DefaultDocumentTreeNode<V> child = (DefaultDocumentTreeNode<V>) children.get(name);
87 + if (child != null) {
88 + return child.value();
89 + }
90 + children.put(name, new DefaultDocumentTreeNode<>(new DocumentPath(name, path()), newValue, newVersion, this));
91 + return null;
113 } 92 }
114 93
115 /** 94 /**
116 - * Removes a child node. 95 + * Updates the node value.
117 * 96 *
118 - * @param child the child node to be removed 97 + * @param newValue new value to set
119 - * @return {@code true} if the child set was modified as a result of this call, {@code false} otherwise 98 + * @param newVersion new version to set
99 + * @return previous value
120 */ 100 */
121 - public boolean removeChild(String child) { 101 + public Versioned<V> update(V newValue, long newVersion) {
122 - return children.remove(child); 102 + Versioned<V> previousValue = value;
103 + value = new Versioned<>(newValue, newVersion);
104 + return previousValue;
123 } 105 }
124 106
107 +
125 /** 108 /**
126 - * Returns the parent of this node. 109 + * Removes a child node.
127 * 110 *
128 - * @return the parent node of this node, which may be null 111 + * @param name the name of child node to be removed
112 + * @return {@code true} if the child set was modified as a result of this call, {@code false} otherwise
129 */ 113 */
130 - public DocumentTreeNode<V> getParent() { 114 + public boolean removeChild(String name) {
131 - return parent; 115 + return children.remove(name) != null;
132 } 116 }
133 117
134 @Override 118 @Override
...@@ -138,16 +122,11 @@ public class DocumentTreeNode<V> { ...@@ -138,16 +122,11 @@ public class DocumentTreeNode<V> {
138 122
139 @Override 123 @Override
140 public boolean equals(Object obj) { 124 public boolean equals(Object obj) {
141 - if (obj instanceof DocumentTreeNode) { 125 + if (obj instanceof DefaultDocumentTreeNode) {
142 - DocumentTreeNode<V> that = (DocumentTreeNode<V>) obj; 126 + DefaultDocumentTreeNode<V> that = (DefaultDocumentTreeNode<V>) obj;
143 if (this.parent.equals(that.parent)) { 127 if (this.parent.equals(that.parent)) {
144 if (this.children.size() == that.children.size()) { 128 if (this.children.size() == that.children.size()) {
145 - for (DocumentTreeNode<V> child : this.children) { 129 + return Sets.symmetricDifference(this.children.keySet(), that.children.keySet()).isEmpty();
146 - if (!that.children.contains(child)) {
147 - return false;
148 - }
149 - }
150 - return true;
151 } 130 }
152 } 131 }
153 } 132 }
...@@ -161,10 +140,9 @@ public class DocumentTreeNode<V> { ...@@ -161,10 +140,9 @@ public class DocumentTreeNode<V> {
161 .add("parent", this.parent) 140 .add("parent", this.parent)
162 .add("key", this.key) 141 .add("key", this.key)
163 .add("value", this.value); 142 .add("value", this.value);
164 - for (DocumentTreeNode<V> child : children) { 143 + for (DocumentTreeNode<V> child : children.values()) {
165 - helper = helper.add("child", child.key); 144 + helper = helper.add("child", child);
166 } 145 }
167 return helper.toString(); 146 return helper.toString();
168 } 147 }
169 -
170 } 148 }
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.primitives.resources.impl;
18 +
19 +import org.junit.Assert;
20 +import org.junit.Test;
21 +import org.onosproject.store.service.DocumentPath;
22 +import org.onosproject.store.service.DocumentTree;
23 +import org.onosproject.store.service.IllegalDocumentModificationException;
24 +import org.onosproject.store.service.NoSuchDocumentPathException;
25 +import org.onosproject.store.service.Versioned;
26 +
27 +/**
28 + * Tests for {@code DefaultDocumentTree}.
29 + */
30 +public class DefaultDocumentTreeTest {
31 +
32 + @Test
33 + public void testTreeConstructor() {
34 + DocumentTree<String> tree = new DefaultDocumentTree<>();
35 + Assert.assertEquals(tree.root(), path("root"));
36 + }
37 +
38 + @Test
39 + public void testCreateNodeAtRoot() {
40 + DocumentTree<String> tree = new DefaultDocumentTree<>();
41 + Assert.assertTrue(tree.create(path("root.a"), "bar"));
42 + Assert.assertFalse(tree.create(path("root.a"), "baz"));
43 + }
44 +
45 + @Test
46 + public void testCreateNodeAtNonRoot() {
47 + DocumentTree<String> tree = new DefaultDocumentTree<>();
48 + tree.create(path("root.a"), "bar");
49 + Assert.assertTrue(tree.create(path("root.a.b"), "baz"));
50 + }
51 +
52 + @Test(expected=IllegalDocumentModificationException.class)
53 + public void testCreateNodeFailure() {
54 + DocumentTree<String> tree = new DefaultDocumentTree<>();
55 + tree.create(path("root.a.b"), "bar");
56 + }
57 +
58 + @Test
59 + public void testGetRootValue() {
60 + DocumentTree<String> tree = new DefaultDocumentTree<>();
61 + tree.create(path("root.a"), "bar");
62 + tree.create(path("root.a.b"), "baz");
63 + Versioned<String> root = tree.get(path("root"));
64 + Assert.assertNotNull(root);
65 + Assert.assertNull(root.value());
66 + }
67 +
68 + @Test
69 + public void testGetInnerNode() {
70 + DocumentTree<String> tree = new DefaultDocumentTree<>();
71 + tree.create(path("root.a"), "bar");
72 + tree.create(path("root.a.b"), "baz");
73 + Versioned<String> nodeValue = tree.get(path("root.a"));
74 + Assert.assertNotNull(nodeValue);
75 + Assert.assertEquals("bar", nodeValue.value());
76 + }
77 +
78 + @Test
79 + public void testGetLeafNode() {
80 + DocumentTree<String> tree = new DefaultDocumentTree<>();
81 + tree.create(path("root.a"), "bar");
82 + tree.create(path("root.a.b"), "baz");
83 + Versioned<String> nodeValue = tree.get(path("root.a.b"));
84 + Assert.assertNotNull(nodeValue);
85 + Assert.assertEquals("baz", nodeValue.value());
86 + }
87 +
88 + @Test
89 + public void getMissingNode() {
90 + DocumentTree<String> tree = new DefaultDocumentTree<>();
91 + tree.create(path("root.a"), "bar");
92 + tree.create(path("root.a.b"), "baz");
93 + Assert.assertNull(tree.get(path("root.x")));
94 + Assert.assertNull(tree.get(path("root.a.x")));
95 + Assert.assertNull(tree.get(path("root.a.b.x")));
96 + }
97 +
98 + @Test
99 + public void testGetChildren() {
100 + DocumentTree<String> tree = new DefaultDocumentTree<>();
101 + tree.create(path("root.a"), "bar");
102 + tree.create(path("root.a.b"), "alpha");
103 + tree.create(path("root.a.c"), "beta");
104 + Assert.assertEquals(2, tree.getChildren(path("root.a")).size());
105 + Assert.assertEquals(0, tree.getChildren(path("root.a.b")).size());
106 + }
107 +
108 + @Test(expected=NoSuchDocumentPathException.class)
109 + public void testGetChildrenFailure() {
110 + DocumentTree<String> tree = new DefaultDocumentTree<>();
111 + tree.create(path("root.a"), "bar");
112 + tree.getChildren(path("root.a.b"));
113 + }
114 +
115 + @Test(expected=IllegalDocumentModificationException.class)
116 + public void testSetRootFailure() {
117 + DocumentTree<String> tree = new DefaultDocumentTree<>();
118 + tree.set(tree.root(), "bar");
119 + }
120 +
121 + @Test
122 + public void testSet() {
123 + DocumentTree<String> tree = new DefaultDocumentTree<>();
124 + tree.create(path("root.a"), "bar");
125 + Assert.assertNull(tree.set(path("root.a.b"), "alpha"));
126 + Assert.assertEquals("alpha", tree.set(path("root.a.b"), "beta").value());
127 + Assert.assertEquals("beta", tree.get(path("root.a.b")).value());
128 + }
129 +
130 + @Test(expected=IllegalDocumentModificationException.class)
131 + public void testSetInvalidNode() {
132 + DocumentTree<String> tree = new DefaultDocumentTree<>();
133 + tree.set(path("root.a.b"), "alpha");
134 + }
135 +
136 + public void testReplaceWithVersion() {
137 + DocumentTree<String> tree = new DefaultDocumentTree<>();
138 + tree.create(path("root.a"), "bar");
139 + tree.create(path("root.a.b"), "alpha");
140 + Versioned<String> value = tree.get(path("root.a.b"));
141 + Assert.assertTrue(tree.replace(path("root.a.b"), "beta", value.version()));
142 + Assert.assertFalse(tree.replace(path("root.a.b"), "beta", value.version()));
143 + Assert.assertFalse(tree.replace(path("root.x"), "beta", 1));
144 + }
145 +
146 + public void testReplaceWithValue() {
147 + DocumentTree<String> tree = new DefaultDocumentTree<>();
148 + tree.create(path("root.a"), "bar");
149 + tree.create(path("root.a.b"), "alpha");
150 + Assert.assertTrue(tree.replace(path("root.a.b"), "beta", "alpha"));
151 + Assert.assertFalse(tree.replace(path("root.a.b"), "beta", "alpha"));
152 + Assert.assertFalse(tree.replace(path("root.x"), "beta", "bar"));
153 + Assert.assertTrue(tree.replace(path("root.x"), "beta", null));
154 + }
155 +
156 + @Test(expected=IllegalDocumentModificationException.class)
157 + public void testRemoveRoot() {
158 + DocumentTree<String> tree = new DefaultDocumentTree<>();
159 + tree.removeNode(tree.root());
160 + }
161 +
162 + @Test
163 + public void testRemove() {
164 + DocumentTree<String> tree = new DefaultDocumentTree<>();
165 + tree.create(path("root.a"), "bar");
166 + tree.create(path("root.a.b"), "alpha");
167 + Assert.assertEquals("alpha", tree.removeNode(path("root.a.b")).value());
168 + Assert.assertEquals(0, tree.getChildren(path("root.a")).size());
169 + }
170 +
171 + @Test(expected=NoSuchDocumentPathException.class)
172 + public void testRemoveInvalidNode() {
173 + DocumentTree<String> tree = new DefaultDocumentTree<>();
174 + tree.removeNode(path("root.a"));
175 + }
176 +
177 + private static DocumentPath path(String path) {
178 + return DocumentPath.from(path);
179 + }
180 +}