blob: 4c1ff6a799910b7a10d1f84b23f6c9a09f92c68f [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
19import java.util.Iterator;
20import java.util.Map;
21import java.util.Objects;
Yuta HIGUCHI1edc36b2018-01-24 23:39:06 -080022import java.util.Optional;
Madan Jampani79924fa2016-09-13 13:57:03 -070023import java.util.concurrent.atomic.AtomicLong;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070024
25import org.onosproject.store.service.DocumentPath;
26import org.onosproject.store.service.DocumentTree;
27import org.onosproject.store.service.DocumentTreeListener;
28import org.onosproject.store.service.DocumentTreeNode;
29import org.onosproject.store.service.IllegalDocumentModificationException;
30import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070031import org.onosproject.store.service.Ordering;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070032import org.onosproject.store.service.Versioned;
33
34import com.google.common.base.Preconditions;
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;
Jordan Haltermand0d80352017-08-10 15:08:27 -070052 root = new DefaultDocumentTreeNode<V>(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) {
56 root = new DefaultDocumentTreeNode<V>(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
Yuta HIGUCHI1edc36b2018-01-24 23:39:06 -0800151 public boolean replace(DocumentPath path, V newValue, V expectedValue) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700152 checkRootModification(path);
Yuta HIGUCHI1edc36b2018-01-24 23:39:06 -0800153 if (Objects.equals(newValue, expectedValue)) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700154 return false;
155 }
156 DocumentTreeNode<V> node = getNode(path);
Yuta HIGUCHI1edc36b2018-01-24 23:39:06 -0800157 V prevValue = Optional.ofNullable(node)
158 .map(DocumentTreeNode::value)
159 .map(Versioned::valueOrNull)
160 .orElse(null);
161 if (Objects.equals(prevValue, expectedValue)) {
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700162 set(path, newValue);
163 return true;
164 }
165 return false;
166 }
167
168 @Override
169 public Versioned<V> removeNode(DocumentPath path) {
170 checkRootModification(path);
171 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
172 if (nodeToRemove == null) {
173 throw new NoSuchDocumentPathException();
174 }
175 if (nodeToRemove.hasChildren()) {
176 throw new IllegalDocumentModificationException();
177 }
178 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
179 parent.removeChild(simpleName(path));
180 return nodeToRemove.value();
181 }
182
183 @Override
184 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
185 // TODO Auto-generated method stub
186 }
187
188 @Override
189 public void removeListener(DocumentTreeListener<V> listener) {
190 // TODO Auto-generated method stub
191 }
192
193 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
194 Iterator<String> pathElements = path.pathElements().iterator();
195 DefaultDocumentTreeNode<V> currentNode = root;
196 Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
197 while (pathElements.hasNext() && currentNode != null) {
198 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
199 }
200 return currentNode;
201 }
202
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700203 private String simpleName(DocumentPath path) {
204 return path.pathElements().get(path.pathElements().size() - 1);
205 }
206
207 private void checkRootModification(DocumentPath path) {
208 if (ROOT_PATH.equals(path)) {
209 throw new IllegalDocumentModificationException();
210 }
211 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700212}