blob: 82098d31a4db7159359c8967afa051903edb014d [file] [log] [blame]
Madan Jampaniad5b8c72016-09-12 15:05:01 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Madan Jampaniad5b8c72016-09-12 15:05:01 -07003 *
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.primitives.resources.impl;
18
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -070019import static com.google.common.base.Preconditions.checkArgument;
20
Madan Jampaniad5b8c72016-09-12 15:05:01 -070021import java.util.Iterator;
22import java.util.Map;
23import java.util.Objects;
Madan Jampani79924fa2016-09-13 13:57:03 -070024import java.util.concurrent.atomic.AtomicLong;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070025
26import org.onosproject.store.service.DocumentPath;
27import org.onosproject.store.service.DocumentTree;
28import org.onosproject.store.service.DocumentTreeListener;
29import org.onosproject.store.service.DocumentTreeNode;
30import org.onosproject.store.service.IllegalDocumentModificationException;
31import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070032import org.onosproject.store.service.Ordering;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070033import org.onosproject.store.service.Versioned;
34
Madan Jampani79924fa2016-09-13 13:57:03 -070035import com.google.common.base.Supplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070036import com.google.common.collect.Maps;
37
38/**
39 * Simple implementation of a {@link DocumentTree}.
40 *
41 * @param <V> tree node value type
42 */
43public class DefaultDocumentTree<V> implements DocumentTree<V> {
44
45 private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
Jordan Halterman2bf177c2017-06-29 01:49:08 -070046 final DefaultDocumentTreeNode<V> root;
Madan Jampani79924fa2016-09-13 13:57:03 -070047 private final Supplier<Long> versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070048
49 public DefaultDocumentTree() {
Madan Jampani79924fa2016-09-13 13:57:03 -070050 AtomicLong versionCounter = new AtomicLong(0);
51 versionSupplier = versionCounter::incrementAndGet;
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -070052 root = new DefaultDocumentTreeNode<>(ROOT_PATH, null, versionSupplier.get(), Ordering.NATURAL, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070053 }
54
Jordan Haltermand0d80352017-08-10 15:08:27 -070055 public DefaultDocumentTree(Supplier<Long> versionSupplier, Ordering ordering) {
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -070056 root = new DefaultDocumentTreeNode<>(ROOT_PATH, null, versionSupplier.get(), ordering, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070057 this.versionSupplier = versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070058 }
59
Jordan Halterman2bf177c2017-06-29 01:49:08 -070060 DefaultDocumentTree(Supplier<Long> versionSupplier, DefaultDocumentTreeNode<V> root) {
61 this.root = root;
62 this.versionSupplier = versionSupplier;
63 }
64
Madan Jampaniad5b8c72016-09-12 15:05:01 -070065 @Override
Jordan Haltermanb0ac5902017-07-30 12:31:01 -070066 public String name() {
67 return null;
68 }
69
70 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -070071 public DocumentPath root() {
72 return ROOT_PATH;
73 }
74
75 @Override
76 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
77 DocumentTreeNode<V> node = getNode(path);
78 if (node != null) {
Jordan Haltermand0d80352017-08-10 15:08:27 -070079 Map<String, Versioned<V>> childrenValues = Maps.newLinkedHashMap();
Madan Jampaniad5b8c72016-09-12 15:05:01 -070080 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
81 return childrenValues;
82 }
83 throw new NoSuchDocumentPathException();
84 }
85
86 @Override
87 public Versioned<V> get(DocumentPath path) {
88 DocumentTreeNode<V> currentNode = getNode(path);
89 return currentNode != null ? currentNode.value() : null;
90 }
91
92 @Override
93 public Versioned<V> set(DocumentPath path, V value) {
94 checkRootModification(path);
95 DefaultDocumentTreeNode<V> node = getNode(path);
96 if (node != null) {
Madan Jampani79924fa2016-09-13 13:57:03 -070097 return node.update(value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -070098 } else {
99 create(path, value);
100 return null;
101 }
102 }
103
104 @Override
105 public boolean create(DocumentPath path, V value) {
106 checkRootModification(path);
107 DocumentTreeNode<V> node = getNode(path);
108 if (node != null) {
109 return false;
110 }
111 DocumentPath parentPath = path.parent();
112 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
113 if (parentNode == null) {
114 throw new IllegalDocumentModificationException();
115 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700116 parentNode.addChild(simpleName(path), value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700117 return true;
118 }
119
120 @Override
Madan Jampani86983282016-09-15 14:55:48 -0700121 public boolean createRecursive(DocumentPath path, V value) {
122 checkRootModification(path);
123 DocumentTreeNode<V> node = getNode(path);
124 if (node != null) {
125 return false;
126 }
127 DocumentPath parentPath = path.parent();
128 if (getNode(parentPath) == null) {
129 createRecursive(parentPath, null);
130 }
131 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
132 if (parentNode == null) {
133 throw new IllegalDocumentModificationException();
134 }
135 parentNode.addChild(simpleName(path), value, versionSupplier.get());
136 return true;
137 }
138
139 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700140 public boolean replace(DocumentPath path, V newValue, long version) {
141 checkRootModification(path);
142 DocumentTreeNode<V> node = getNode(path);
143 if (node != null && node.value() != null && node.value().version() == version) {
Jordan Halterman9052b202017-08-01 09:41:32 -0700144 set(path, newValue);
145 return true;
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700146 }
147 return false;
148 }
149
150 @Override
151 public boolean replace(DocumentPath path, V newValue, V currentValue) {
152 checkRootModification(path);
153 if (Objects.equals(newValue, currentValue)) {
154 return false;
155 }
156 DocumentTreeNode<V> node = getNode(path);
157 if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
158 set(path, newValue);
159 return true;
160 }
161 return false;
162 }
163
164 @Override
165 public Versioned<V> removeNode(DocumentPath path) {
166 checkRootModification(path);
167 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
168 if (nodeToRemove == null) {
169 throw new NoSuchDocumentPathException();
170 }
171 if (nodeToRemove.hasChildren()) {
172 throw new IllegalDocumentModificationException();
173 }
174 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
175 parent.removeChild(simpleName(path));
176 return nodeToRemove.value();
177 }
178
179 @Override
180 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
181 // TODO Auto-generated method stub
182 }
183
184 @Override
185 public void removeListener(DocumentTreeListener<V> listener) {
186 // TODO Auto-generated method stub
187 }
188
189 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
190 Iterator<String> pathElements = path.pathElements().iterator();
191 DefaultDocumentTreeNode<V> currentNode = root;
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -0700192 checkArgument("root".equals(pathElements.next()), "Path should start with root: %s", path);
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700193 while (pathElements.hasNext() && currentNode != null) {
194 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
195 }
196 return currentNode;
197 }
198
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700199 private String simpleName(DocumentPath path) {
200 return path.pathElements().get(path.pathElements().size() - 1);
201 }
202
203 private void checkRootModification(DocumentPath path) {
204 if (ROOT_PATH.equals(path)) {
205 throw new IllegalDocumentModificationException();
206 }
207 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700208}