blob: 6589a988abf6a9a307970d5b267ab7acf68cea9b [file] [log] [blame]
Madan Jampaniad5b8c72016-09-12 15:05:01 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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");
44 private 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
58 @Override
59 public DocumentPath root() {
60 return ROOT_PATH;
61 }
62
63 @Override
64 public Map<String, Versioned<V>> getChildren(DocumentPath path) {
65 DocumentTreeNode<V> node = getNode(path);
66 if (node != null) {
67 Map<String, Versioned<V>> childrenValues = Maps.newHashMap();
68 node.children().forEachRemaining(n -> childrenValues.put(simpleName(n.path()), n.value()));
69 return childrenValues;
70 }
71 throw new NoSuchDocumentPathException();
72 }
73
74 @Override
75 public Versioned<V> get(DocumentPath path) {
76 DocumentTreeNode<V> currentNode = getNode(path);
77 return currentNode != null ? currentNode.value() : null;
78 }
79
80 @Override
81 public Versioned<V> set(DocumentPath path, V value) {
82 checkRootModification(path);
83 DefaultDocumentTreeNode<V> node = getNode(path);
84 if (node != null) {
Madan Jampani79924fa2016-09-13 13:57:03 -070085 return node.update(value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -070086 } else {
87 create(path, value);
88 return null;
89 }
90 }
91
92 @Override
93 public boolean create(DocumentPath path, V value) {
94 checkRootModification(path);
95 DocumentTreeNode<V> node = getNode(path);
96 if (node != null) {
97 return false;
98 }
99 DocumentPath parentPath = path.parent();
100 DefaultDocumentTreeNode<V> parentNode = getNode(parentPath);
101 if (parentNode == null) {
102 throw new IllegalDocumentModificationException();
103 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700104 parentNode.addChild(simpleName(path), value, versionSupplier.get());
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700105 return true;
106 }
107
108 @Override
109 public boolean replace(DocumentPath path, V newValue, long version) {
110 checkRootModification(path);
111 DocumentTreeNode<V> node = getNode(path);
112 if (node != null && node.value() != null && node.value().version() == version) {
113 if (!Objects.equals(newValue, node.value().value())) {
114 set(path, newValue);
115 return true;
116 }
117 }
118 return false;
119 }
120
121 @Override
122 public boolean replace(DocumentPath path, V newValue, V currentValue) {
123 checkRootModification(path);
124 if (Objects.equals(newValue, currentValue)) {
125 return false;
126 }
127 DocumentTreeNode<V> node = getNode(path);
128 if (node != null && Objects.equals(Versioned.valueOrNull(node.value()), currentValue)) {
129 set(path, newValue);
130 return true;
131 }
132 return false;
133 }
134
135 @Override
136 public Versioned<V> removeNode(DocumentPath path) {
137 checkRootModification(path);
138 DefaultDocumentTreeNode<V> nodeToRemove = getNode(path);
139 if (nodeToRemove == null) {
140 throw new NoSuchDocumentPathException();
141 }
142 if (nodeToRemove.hasChildren()) {
143 throw new IllegalDocumentModificationException();
144 }
145 DefaultDocumentTreeNode<V> parent = (DefaultDocumentTreeNode<V>) nodeToRemove.parent();
146 parent.removeChild(simpleName(path));
147 return nodeToRemove.value();
148 }
149
150 @Override
151 public void addListener(DocumentPath path, DocumentTreeListener<V> listener) {
152 // TODO Auto-generated method stub
153 }
154
155 @Override
156 public void removeListener(DocumentTreeListener<V> listener) {
157 // TODO Auto-generated method stub
158 }
159
160 private DefaultDocumentTreeNode<V> getNode(DocumentPath path) {
161 Iterator<String> pathElements = path.pathElements().iterator();
162 DefaultDocumentTreeNode<V> currentNode = root;
163 Preconditions.checkState("root".equals(pathElements.next()), "Path should start with root");
164 while (pathElements.hasNext() && currentNode != null) {
165 currentNode = (DefaultDocumentTreeNode<V>) currentNode.child(pathElements.next());
166 }
167 return currentNode;
168 }
169
Madan Jampaniad5b8c72016-09-12 15:05:01 -0700170 private String simpleName(DocumentPath path) {
171 return path.pathElements().get(path.pathElements().size() - 1);
172 }
173
174 private void checkRootModification(DocumentPath path) {
175 if (ROOT_PATH.equals(path)) {
176 throw new IllegalDocumentModificationException();
177 }
178 }
179}