blob: 2d5832ce93d621d78b7beaec6871fd2667a3e100 [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;
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -080024import java.util.Optional;
Madan Jampani79924fa2016-09-13 13:57:03 -070025import java.util.concurrent.atomic.AtomicLong;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070026
27import org.onosproject.store.service.DocumentPath;
28import org.onosproject.store.service.DocumentTree;
29import org.onosproject.store.service.DocumentTreeListener;
30import org.onosproject.store.service.DocumentTreeNode;
31import org.onosproject.store.service.IllegalDocumentModificationException;
32import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070033import org.onosproject.store.service.Ordering;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070034import org.onosproject.store.service.Versioned;
35
Madan Jampani79924fa2016-09-13 13:57:03 -070036import com.google.common.base.Supplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070037import com.google.common.collect.Maps;
38
39/**
40 * Simple implementation of a {@link DocumentTree}.
41 *
42 * @param <V> tree node value type
43 */
44public class DefaultDocumentTree<V> implements DocumentTree<V> {
45
46 private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
Jordan Halterman2bf177c2017-06-29 01:49:08 -070047 final DefaultDocumentTreeNode<V> root;
Madan Jampani79924fa2016-09-13 13:57:03 -070048 private final Supplier<Long> versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070049
50 public DefaultDocumentTree() {
Madan Jampani79924fa2016-09-13 13:57:03 -070051 AtomicLong versionCounter = new AtomicLong(0);
52 versionSupplier = versionCounter::incrementAndGet;
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -070053 root = new DefaultDocumentTreeNode<>(ROOT_PATH, null, versionSupplier.get(), Ordering.NATURAL, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070054 }
55
Jordan Haltermand0d80352017-08-10 15:08:27 -070056 public DefaultDocumentTree(Supplier<Long> versionSupplier, Ordering ordering) {
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -070057 root = new DefaultDocumentTreeNode<>(ROOT_PATH, null, versionSupplier.get(), ordering, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070058 this.versionSupplier = versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070059 }
60
Jordan Halterman2bf177c2017-06-29 01:49:08 -070061 DefaultDocumentTree(Supplier<Long> versionSupplier, DefaultDocumentTreeNode<V> root) {
62 this.root = root;
63 this.versionSupplier = versionSupplier;
64 }
65
Madan Jampaniad5b8c72016-09-12 15:05:01 -070066 @Override
Jordan Haltermanb0ac5902017-07-30 12:31:01 -070067 public String name() {
68 return null;
69 }
70
71 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -070072 public DocumentPath root() {
73 return ROOT_PATH;
74 }
75
76 @Override
77 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
78 DocumentTreeNode<V> node = getNode(path);
79 if (node != null) {
Jordan Haltermand0d80352017-08-10 15:08:27 -070080 Map<String, Versioned<V>> childrenValues = Maps.newLinkedHashMap();
Madan Jampaniad5b8c72016-09-12 15:05:01 -070081 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
82 return childrenValues;
83 }
84 throw new NoSuchDocumentPathException();
85 }
86
87 @Override
88 public Versioned<V> get(DocumentPath path) {
89 DocumentTreeNode<V> currentNode = getNode(path);
90 return currentNode != null ? currentNode.value() : null;
91 }
92
93 @Override
94 public Versioned<V> set(DocumentPath path, V value) {
95 checkRootModification(path);
96 DefaultDocumentTreeNode<V> node = getNode(path);
97 if (node != null) {
Madan Jampani79924fa2016-09-13 13:57:03 -070098 return node.update(value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -070099 } else {
100 create(path, value);
101 return null;
102 }
103 }
104
105 @Override
106 public boolean create(DocumentPath path, V value) {
107 checkRootModification(path);
108 DocumentTreeNode<V> node = getNode(path);
109 if (node != null) {
110 return false;
111 }
112 DocumentPath parentPath = path.parent();
113 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
114 if (parentNode == null) {
115 throw new IllegalDocumentModificationException();
116 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700117 parentNode.addChild(simpleName(path), value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700118 return true;
119 }
120
121 @Override
Madan Jampani86983282016-09-15 14:55:48 -0700122 public boolean createRecursive(DocumentPath path, V value) {
123 checkRootModification(path);
124 DocumentTreeNode<V> node = getNode(path);
125 if (node != null) {
126 return false;
127 }
128 DocumentPath parentPath = path.parent();
129 if (getNode(parentPath) == null) {
130 createRecursive(parentPath, null);
131 }
132 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
133 if (parentNode == null) {
134 throw new IllegalDocumentModificationException();
135 }
136 parentNode.addChild(simpleName(path), value, versionSupplier.get());
137 return true;
138 }
139
140 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700141 public boolean replace(DocumentPath path, V newValue, long version) {
142 checkRootModification(path);
143 DocumentTreeNode<V> node = getNode(path);
144 if (node != null && node.value() != null && node.value().version() == version) {
Jordan Halterman9052b202017-08-01 09:41:32 -0700145 set(path, newValue);
146 return true;
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700147 }
148 return false;
149 }
150
151 @Override
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -0800152 public boolean replace(DocumentPath path, V newValue, V expectedValue) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700153 checkRootModification(path);
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -0800154 if (Objects.equals(newValue, expectedValue)) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700155 return false;
156 }
157 DocumentTreeNode<V> node = getNode(path);
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -0800158 V prevValue = Optional.ofNullable(node)
159 .map(DocumentTreeNode::value)
160 .map(Versioned::valueOrNull)
161 .orElse(null);
162 if (Objects.equals(prevValue, expectedValue)) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700163 set(path, newValue);
164 return true;
165 }
166 return false;
167 }
168
169 @Override
170 public Versioned<V> removeNode(DocumentPath path) {
171 checkRootModification(path);
172 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
173 if (nodeToRemove == null) {
174 throw new NoSuchDocumentPathException();
175 }
176 if (nodeToRemove.hasChildren()) {
177 throw new IllegalDocumentModificationException();
178 }
179 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
180 parent.removeChild(simpleName(path));
181 return nodeToRemove.value();
182 }
183
184 @Override
185 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
186 // TODO Auto-generated method stub
187 }
188
189 @Override
190 public void removeListener(DocumentTreeListener<V> listener) {
191 // TODO Auto-generated method stub
192 }
193
194 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
195 Iterator<String> pathElements = path.pathElements().iterator();
196 DefaultDocumentTreeNode<V> currentNode = root;
Yuta HIGUCHI6b2ec282017-11-03 21:08:38 -0700197 checkArgument("root".equals(pathElements.next()), "Path should start with root: %s", path);
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700198 while (pathElements.hasNext() && currentNode != null) {
199 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
200 }
201 return currentNode;
202 }
203
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700204 private String simpleName(DocumentPath path) {
205 return path.pathElements().get(path.pathElements().size() - 1);
206 }
207
208 private void checkRootModification(DocumentPath path) {
209 if (ROOT_PATH.equals(path)) {
210 throw new IllegalDocumentModificationException();
211 }
212 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700213}