blob: 3ead9e62559d2fd8c11b5c3df30299dbac8ddad5 [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;
30import org.onosproject.store.service.Versioned;
31
32import com.google.common.base.Preconditions;
Madan Jampani79924fa2016-09-13 13:57:03 -070033import com.google.common.base.Supplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070034import com.google.common.collect.Maps;
35
36/**
37 * Simple implementation of a {@link DocumentTree}.
38 *
39 * @param <V> tree node value type
40 */
41public class DefaultDocumentTree<V> implements DocumentTree<V> {
42
43 private static final DocumentPath ROOT_PATH = DocumentPath.from("root");
Jordan Halterman2bf177c2017-06-29 01:49:08 -070044 final DefaultDocumentTreeNode<V> root;
Madan Jampani79924fa2016-09-13 13:57:03 -070045 private final Supplier<Long> versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070046
47 public DefaultDocumentTree() {
Madan Jampani79924fa2016-09-13 13:57:03 -070048 AtomicLong versionCounter = new AtomicLong(0);
49 versionSupplier = versionCounter::incrementAndGet;
50 root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), null);
51 }
52
53 public DefaultDocumentTree(Supplier<Long> versionSupplier) {
54 root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), null);
55 this.versionSupplier = versionSupplier;
Madan Jampaniad5b8c72016-09-12 15:05:01 -070056 }
57
Jordan Halterman2bf177c2017-06-29 01:49:08 -070058 DefaultDocumentTree(Supplier<Long> versionSupplier, DefaultDocumentTreeNode<V> root) {
59 this.root = root;
60 this.versionSupplier = versionSupplier;
61 }
62
Madan Jampaniad5b8c72016-09-12 15:05:01 -070063 @Override
Jordan Haltermanb0ac5902017-07-30 12:31:01 -070064 public String name() {
65 return null;
66 }
67
68 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -070069 public DocumentPath root() {
70 return ROOT_PATH;
71 }
72
73 @Override
74 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
75 DocumentTreeNode<V> node = getNode(path);
76 if (node != null) {
77 Map<String, Versioned<V>> childrenValues = Maps.newHashMap();
78 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
79 return childrenValues;
80 }
81 throw new NoSuchDocumentPathException();
82 }
83
84 @Override
85 public Versioned<V> get(DocumentPath path) {
86 DocumentTreeNode<V> currentNode = getNode(path);
87 return currentNode != null ? currentNode.value() : null;
88 }
89
90 @Override
91 public Versioned<V> set(DocumentPath path, V value) {
92 checkRootModification(path);
93 DefaultDocumentTreeNode<V> node = getNode(path);
94 if (node != null) {
Madan Jampani79924fa2016-09-13 13:57:03 -070095 return node.update(value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -070096 } else {
97 create(path, value);
98 return null;
99 }
100 }
101
102 @Override
103 public boolean create(DocumentPath path, V value) {
104 checkRootModification(path);
105 DocumentTreeNode<V> node = getNode(path);
106 if (node != null) {
107 return false;
108 }
109 DocumentPath parentPath = path.parent();
110 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
111 if (parentNode == null) {
112 throw new IllegalDocumentModificationException();
113 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700114 parentNode.addChild(simpleName(path), value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700115 return true;
116 }
117
118 @Override
Madan Jampani86983282016-09-15 14:55:48 -0700119 public boolean createRecursive(DocumentPath path, V value) {
120 checkRootModification(path);
121 DocumentTreeNode<V> node = getNode(path);
122 if (node != null) {
123 return false;
124 }
125 DocumentPath parentPath = path.parent();
126 if (getNode(parentPath) == null) {
127 createRecursive(parentPath, null);
128 }
129 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
130 if (parentNode == null) {
131 throw new IllegalDocumentModificationException();
132 }
133 parentNode.addChild(simpleName(path), value, versionSupplier.get());
134 return true;
135 }
136
137 @Override
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700138 public boolean replace(DocumentPath path, V newValue, long version) {
139 checkRootModification(path);
140 DocumentTreeNode<V> node = getNode(path);
141 if (node != null && node.value() != null && node.value().version() == version) {
Jordan Halterman9052b202017-08-01 09:41:32 -0700142 set(path, newValue);
143 return true;
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700144 }
145 return false;
146 }
147
148 @Override
149 public boolean replace(DocumentPath path, V newValue, V currentValue) {
150 checkRootModification(path);
151 if (Objects.equals(newValue, currentValue)) {
152 return false;
153 }
154 DocumentTreeNode<V> node = getNode(path);
155 if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
156 set(path, newValue);
157 return true;
158 }
159 return false;
160 }
161
162 @Override
163 public Versioned<V> removeNode(DocumentPath path) {
164 checkRootModification(path);
165 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
166 if (nodeToRemove == null) {
167 throw new NoSuchDocumentPathException();
168 }
169 if (nodeToRemove.hasChildren()) {
170 throw new IllegalDocumentModificationException();
171 }
172 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
173 parent.removeChild(simpleName(path));
174 return nodeToRemove.value();
175 }
176
177 @Override
178 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
179 // TODO Auto-generated method stub
180 }
181
182 @Override
183 public void removeListener(DocumentTreeListener<V> listener) {
184 // TODO Auto-generated method stub
185 }
186
187 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
188 Iterator<String> pathElements = path.pathElements().iterator();
189 DefaultDocumentTreeNode<V> currentNode = root;
190 Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
191 while (pathElements.hasNext() && currentNode != null) {
192 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
193 }
194 return currentNode;
195 }
196
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700197 private String simpleName(DocumentPath path) {
198 return path.pathElements().get(path.pathElements().size() - 1);
199 }
200
201 private void checkRootModification(DocumentPath path) {
202 if (ROOT_PATH.equals(path)) {
203 throw new IllegalDocumentModificationException();
204 }
205 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700206}