blob: 31bd20c794088877b86db568ccbbd1b3c734e9e3 [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;
Madan Jampani79924fa2016-09-13 13:57:03 -070022import java.util.concurrent.atomic.AtomicLong;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070023
24import org.onosproject.store.service.DocumentPath;
25import org.onosproject.store.service.DocumentTree;
26import org.onosproject.store.service.DocumentTreeListener;
27import org.onosproject.store.service.DocumentTreeNode;
28import org.onosproject.store.service.IllegalDocumentModificationException;
29import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070030import org.onosproject.store.service.Ordering;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070031import org.onosproject.store.service.Versioned;
32
33import com.google.common.base.Preconditions;
Madan Jampani79924fa2016-09-13 13:57:03 -070034import com.google.common.base.Supplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070035import com.google.common.collect.Maps;
36
37/**
38 * Simple implementation of a {@link DocumentTree}.
39 *
40 * @param <V> tree node value type
41 */
42public class DefaultDocumentTree<V> implements DocumentTree<V> {
43
44 private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
Jordan Halterman2bf177c2017-06-29 01:49:08 -070045 final DefaultDocumentTreeNode<V> root;
Madan Jampani79924fa2016-09-13 13:57:03 -070046 private final Supplier<Long> versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070047
48 public DefaultDocumentTree() {
Madan Jampani79924fa2016-09-13 13:57:03 -070049 AtomicLong versionCounter = new AtomicLong(0);
50 versionSupplier = versionCounter::incrementAndGet;
Jordan Haltermand0d80352017-08-10 15:08:27 -070051 root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), Ordering.NATURAL, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070052 }
53
Jordan Haltermand0d80352017-08-10 15:08:27 -070054 public DefaultDocumentTree(Supplier<Long> versionSupplier, Ordering ordering) {
55 root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), ordering, null);
Madan Jampani79924fa2016-09-13 13:57:03 -070056 this.versionSupplier = versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070057 }
58
Jordan Halterman2bf177c2017-06-29 01:49:08 -070059 DefaultDocumentTree(Supplier<Long> versionSupplier, DefaultDocumentTreeNode<V> root) {
60 this.root = root;
61 this.versionSupplier = versionSupplier;
62 }
63
Madan Jampaniad5b8c72016-09-12 15:05:01 -070064 @Override
Jordan Haltermanb0ac5902017-07-30 12:31:01 -070065 public String name() {
66 return null;
67 }
68
69 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -070070 public DocumentPath root() {
71 return ROOT_PATH;
72 }
73
74 @Override
75 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
76 DocumentTreeNode<V> node = getNode(path);
77 if (node != null) {
Jordan Haltermand0d80352017-08-10 15:08:27 -070078 Map<String, Versioned<V>> childrenValues = Maps.newLinkedHashMap();
Madan Jampaniad5b8c72016-09-12 15:05:01 -070079 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
80 return childrenValues;
81 }
82 throw new NoSuchDocumentPathException();
83 }
84
85 @Override
86 public Versioned<V> get(DocumentPath path) {
87 DocumentTreeNode<V> currentNode = getNode(path);
88 return currentNode != null ? currentNode.value() : null;
89 }
90
91 @Override
92 public Versioned<V> set(DocumentPath path, V value) {
93 checkRootModification(path);
94 DefaultDocumentTreeNode<V> node = getNode(path);
95 if (node != null) {
Madan Jampani79924fa2016-09-13 13:57:03 -070096 return node.update(value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -070097 } else {
98 create(path, value);
99 return null;
100 }
101 }
102
103 @Override
104 public boolean create(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 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
112 if (parentNode == null) {
113 throw new IllegalDocumentModificationException();
114 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700115 parentNode.addChild(simpleName(path), value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700116 return true;
117 }
118
119 @Override
Madan Jampani86983282016-09-15 14:55:48 -0700120 public boolean createRecursive(DocumentPath path, V value) {
121 checkRootModification(path);
122 DocumentTreeNode<V> node = getNode(path);
123 if (node != null) {
124 return false;
125 }
126 DocumentPath parentPath = path.parent();
127 if (getNode(parentPath) == null) {
128 createRecursive(parentPath, null);
129 }
130 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
131 if (parentNode == null) {
132 throw new IllegalDocumentModificationException();
133 }
134 parentNode.addChild(simpleName(path), value, versionSupplier.get());
135 return true;
136 }
137
138 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700139 public boolean replace(DocumentPath path, V newValue, long version) {
140 checkRootModification(path);
141 DocumentTreeNode<V> node = getNode(path);
142 if (node != null && node.value() != null && node.value().version() == version) {
Jordan Halterman9052b202017-08-01 09:41:32 -0700143 set(path, newValue);
144 return true;
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700145 }
146 return false;
147 }
148
149 @Override
150 public boolean replace(DocumentPath path, V newValue, V currentValue) {
151 checkRootModification(path);
152 if (Objects.equals(newValue, currentValue)) {
153 return false;
154 }
155 DocumentTreeNode<V> node = getNode(path);
156 if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
157 set(path, newValue);
158 return true;
159 }
160 return false;
161 }
162
163 @Override
164 public Versioned<V> removeNode(DocumentPath path) {
165 checkRootModification(path);
166 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
167 if (nodeToRemove == null) {
168 throw new NoSuchDocumentPathException();
169 }
170 if (nodeToRemove.hasChildren()) {
171 throw new IllegalDocumentModificationException();
172 }
173 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
174 parent.removeChild(simpleName(path));
175 return nodeToRemove.value();
176 }
177
178 @Override
179 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
180 // TODO Auto-generated method stub
181 }
182
183 @Override
184 public void removeListener(DocumentTreeListener<V> listener) {
185 // TODO Auto-generated method stub
186 }
187
188 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
189 Iterator<String> pathElements = path.pathElements().iterator();
190 DefaultDocumentTreeNode<V> currentNode = root;
191 Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
192 while (pathElements.hasNext() && currentNode != null) {
193 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
194 }
195 return currentNode;
196 }
197
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700198 private String simpleName(DocumentPath path) {
199 return path.pathElements().get(path.pathElements().size() - 1);
200 }
201
202 private void checkRootModification(DocumentPath path) {
203 if (ROOT_PATH.equals(path)) {
204 throw new IllegalDocumentModificationException();
205 }
206 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700207}