blob: c9100f5d7c849553f9738c610b719be437c9f3aa [file] [log] [blame]
Jordan Haltermanf7554092017-07-30 15:05:51 -07001/*
2 * Copyright 2017-present Open Networking Foundation
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
17package org.onosproject.store.service;
18
19import java.util.Iterator;
20import java.util.Map;
21import java.util.Objects;
22import java.util.concurrent.atomic.AtomicLong;
23
24import com.google.common.base.Preconditions;
25import com.google.common.collect.Maps;
26
27/**
28 * Simple implementation of a {@link DocumentTree}.
29 *
30 * @param <V> tree node value type
31 */
32public class TestDocumentTree<V> implements DocumentTree<V> {
33
34 private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
35 private final String name;
36 final TestDocumentTreeNode<V> root;
37 private final AtomicLong version = new AtomicLong();
38
39 public TestDocumentTree(String name) {
40 this(name, null);
41 }
42
43 public TestDocumentTree(String name, V value) {
44 this.name = name;
45 this.root = new TestDocumentTreeNode<>(ROOT_PATH, value, version.incrementAndGet(), null);
46 }
47
48 @Override
49 public String name() {
50 return name;
51 }
52
53 @Override
54 public DocumentPath root() {
55 return ROOT_PATH;
56 }
57
58 @Override
59 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
60 DocumentTreeNode<V> node = getNode(path);
61 if (node != null) {
62 Map<String, Versioned<V>> childrenValues = Maps.newHashMap();
63 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
64 return childrenValues;
65 }
66 throw new NoSuchDocumentPathException();
67 }
68
69 @Override
70 public Versioned<V> get(DocumentPath path) {
71 DocumentTreeNode<V> currentNode = getNode(path);
72 return currentNode != null ? currentNode.value() : null;
73 }
74
75 @Override
76 public Versioned<V> set(DocumentPath path, V value) {
77 checkRootModification(path);
78 TestDocumentTreeNode<V> node = getNode(path);
79 if (node != null) {
80 return node.update(value, version.incrementAndGet());
81 } else {
82 create(path, value);
83 return null;
84 }
85 }
86
87 @Override
88 public boolean create(DocumentPath path, V value) {
89 checkRootModification(path);
90 DocumentTreeNode<V> node = getNode(path);
91 if (node != null) {
92 return false;
93 }
94 DocumentPath parentPath = path.parent();
95 TestDocumentTreeNode<V> parentNode = getNode(parentPath);
96 if (parentNode == null) {
97 throw new IllegalDocumentModificationException();
98 }
99 parentNode.addChild(simpleName(path), value, version.incrementAndGet());
100 return true;
101 }
102
103 @Override
104 public boolean createRecursive(DocumentPath path, V value) {
105 checkRootModification(path);
106 DocumentTreeNode<V> node = getNode(path);
107 if (node != null) {
108 return false;
109 }
110 DocumentPath parentPath = path.parent();
111 if (getNode(parentPath) == null) {
112 createRecursive(parentPath, null);
113 }
114 TestDocumentTreeNode<V> parentNode = getNode(parentPath);
115 if (parentNode == null) {
116 throw new IllegalDocumentModificationException();
117 }
118 parentNode.addChild(simpleName(path), value, version.incrementAndGet());
119 return true;
120 }
121
122 @Override
123 public boolean replace(DocumentPath path, V newValue, long version) {
124 checkRootModification(path);
125 DocumentTreeNode<V> node = getNode(path);
126 if (node != null && node.value() != null && node.value().version() == version) {
127 set(path, newValue);
128 return true;
129 }
130 return false;
131 }
132
133 @Override
134 public boolean replace(DocumentPath path, V newValue, V currentValue) {
135 checkRootModification(path);
136 if (Objects.equals(newValue, currentValue)) {
137 return false;
138 }
139 DocumentTreeNode<V> node = getNode(path);
140 if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
141 set(path, newValue);
142 return true;
143 }
144 return false;
145 }
146
147 @Override
148 public Versioned<V> removeNode(DocumentPath path) {
149 checkRootModification(path);
150 TestDocumentTreeNode<V> nodeToRemove = getNode(path);
151 if (nodeToRemove == null) {
152 throw new NoSuchDocumentPathException();
153 }
154 if (nodeToRemove.hasChildren()) {
155 throw new IllegalDocumentModificationException();
156 }
157 TestDocumentTreeNode<V> parent = (TestDocumentTreeNode<V>) nodeToRemove.parent();
158 parent.removeChild(simpleName(path));
159 return nodeToRemove.value();
160 }
161
162 @Override
163 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
164 // TODO Auto-generated method stub
165 }
166
167 @Override
168 public void removeListener(DocumentTreeListener<V> listener) {
169 // TODO Auto-generated method stub
170 }
171
172 private TestDocumentTreeNode<V> getNode(DocumentPath path) {
173 Iterator<String> pathElements = path.pathElements().iterator();
174 TestDocumentTreeNode<V> currentNode = root;
175 Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
176 while (pathElements.hasNext() && currentNode != null) {
177 currentNode = (TestDocumentTreeNode<V>) currentNode.child(pathElements.next());
178 }
179 return currentNode;
180 }
181
182 private String simpleName(DocumentPath path) {
183 return path.pathElements().get(path.pathElements().size() - 1);
184 }
185
186 private void checkRootModification(DocumentPath path) {
187 if (ROOT_PATH.equals(path)) {
188 throw new IllegalDocumentModificationException();
189 }
190 }
191}