blob: c960646579a907fa6e4c6cd56677733a7deffc4a [file] [log] [blame]
Sithara Punnassery9306e6b2017-02-06 15:38:19 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Sithara Punnassery9306e6b2017-02-06 15:38:19 -08003 *
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 *
Sithara Punnassery61a80252017-08-07 11:16:08 -07008 * http://www.apache.org/licenses/LICENSE-2.0
Sithara Punnassery9306e6b2017-02-06 15:38:19 -08009 *
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 */
16package org.onosproject.config.impl;
17
Sithara Punnassery06208792017-02-10 16:25:29 -080018import com.google.common.annotations.Beta;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.util.KryoNamespace;
26import org.onosproject.config.DynamicConfigEvent;
27import org.onosproject.config.DynamicConfigStore;
28import org.onosproject.config.DynamicConfigStoreDelegate;
29import org.onosproject.config.FailedException;
30import org.onosproject.config.Filter;
Henry Yu5c54e772017-04-19 14:13:56 -040031import org.onosproject.config.ResourceIdParser;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070032import org.onosproject.d.config.ResourceIds;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080033import org.onosproject.store.AbstractStore;
34import org.onosproject.store.serializers.KryoNamespaces;
35import org.onosproject.store.service.AsyncDocumentTree;
36import org.onosproject.store.service.ConsistentMap;
37import org.onosproject.store.service.DocumentPath;
38import org.onosproject.store.service.DocumentTreeEvent;
39import org.onosproject.store.service.DocumentTreeListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080040import org.onosproject.store.service.IllegalDocumentModificationException;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080041import org.onosproject.store.service.MapEvent;
42import org.onosproject.store.service.MapEventListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080043import org.onosproject.store.service.NoSuchDocumentPathException;
Sithara Punnasserydb3591b2017-08-10 19:44:53 -070044import org.onosproject.store.service.Ordering;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080045import org.onosproject.store.service.Serializer;
46import org.onosproject.store.service.StorageService;
47import org.onosproject.store.service.Versioned;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080048import org.onosproject.yang.model.DataNode;
49import org.onosproject.yang.model.InnerNode;
50import org.onosproject.yang.model.KeyLeaf;
51import org.onosproject.yang.model.LeafListKey;
52import org.onosproject.yang.model.LeafNode;
Yuta HIGUCHIf662e312018-02-12 17:04:28 -080053import org.onosproject.yang.model.LeafType;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080054import org.onosproject.yang.model.ListKey;
55import org.onosproject.yang.model.NodeKey;
56import org.onosproject.yang.model.ResourceId;
57import org.onosproject.yang.model.SchemaId;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
Henry Yu5c54e772017-04-19 14:13:56 -040060
Gaurav Agrawalc3445a12017-11-16 20:37:58 +053061import java.math.BigDecimal;
Henry Yu5c54e772017-04-19 14:13:56 -040062import java.math.BigInteger;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070063import java.util.LinkedHashMap;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080064import java.util.Map;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070065import java.util.Optional;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080066import java.util.concurrent.CompletableFuture;
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080067import java.util.concurrent.ExecutionException;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080068import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080069import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
Henry Yu5c54e772017-04-19 14:13:56 -040070import static org.onosproject.config.DynamicConfigEvent.Type.NODE_UPDATED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080071import static org.onosproject.config.DynamicConfigEvent.Type.UNKNOWN_OPRN;
72
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080073/**
74 * Implementation of the dynamic config store.
75 */
Sithara Punnassery06208792017-02-10 16:25:29 -080076@Beta
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080077@Component(immediate = true)
78@Service
79public class DistributedDynamicConfigStore
80 extends AbstractStore<DynamicConfigEvent, DynamicConfigStoreDelegate>
81 implements DynamicConfigStore {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070082
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080083 private final Logger log = LoggerFactory.getLogger(getClass());
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070084
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected StorageService storageService;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070087
88 // FIXME transactionally mutate the 2 or consolidate into 1 AsyncDocTree
89 // effectively tree structure only
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080090 private AsyncDocumentTree<DataNode.Type> keystore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070091 // TODO Can we pass DocumentPath directly to ConsistentMap?
92 // Map<DocumentPath as String, leaf value>
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080093 private ConsistentMap<String, LeafNode> objectStore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070094
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080095 private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080096 private final MapEventListener<String, LeafNode> olistener = new InternalMapListener();
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080097
98 @Activate
99 public void activateStore() {
100 KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
101 .register(KryoNamespaces.BASIC)
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700102 .register(Class.class)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800103 .register(DataNode.Type.class)
104 .register(LeafNode.class)
105 .register(InnerNode.class)
106 .register(ResourceId.class)
107 .register(NodeKey.class)
108 .register(SchemaId.class)
Sithara Punnassery43833e12017-03-14 16:29:19 -0700109 .register(LeafListKey.class)
110 .register(ListKey.class)
111 .register(KeyLeaf.class)
Henry Yu5c54e772017-04-19 14:13:56 -0400112 .register(BigInteger.class)
Gaurav Agrawalc3445a12017-11-16 20:37:58 +0530113 .register(BigDecimal.class)
Yuta HIGUCHIf662e312018-02-12 17:04:28 -0800114 .register(LinkedHashMap.class)
115 .register(LeafType.class);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800116 keystore = storageService.<DataNode.Type>documentTreeBuilder()
117 .withSerializer(Serializer.using(kryoBuilder.build()))
118 .withName("config-key-store")
119 .withRelaxedReadConsistency()
Sithara Punnasserydb3591b2017-08-10 19:44:53 -0700120 .withOrdering(Ordering.INSERTION)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800121 .buildDocumentTree();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800122 objectStore = storageService.<String, LeafNode>consistentMapBuilder()
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800123 .withSerializer(Serializer.using(kryoBuilder.build()))
124 .withName("config-object-store")
125 .withRelaxedReadConsistency()
126 .build();
127 keystore.addListener(klistener);
128 objectStore.addListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700129 log.info("Started");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800130 }
131
132 @Deactivate
133 public void deactivateStore() {
134 keystore.removeListener(klistener);
135 objectStore.removeListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700136 log.info("Stopped");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800137 }
138
139 @Override
140 public CompletableFuture<Boolean>
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700141 addNode(ResourceId parent, DataNode node) {
142 String spath = ResourceIdParser.parseResId(parent);
143 log.trace(" addNode({}, {})", parent, node);
144 log.trace(" spath={}", spath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800145 if (spath == null) {
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700146 throw new FailedException("Invalid ResourceId, cannot create Node");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800147 }
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700148 if (!spath.equals(ResourceIdParser.ROOT)) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700149 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700150 throw new FailedException("Node or parent does not exist for " + spath);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700151 }
Sithara Punnasserybb644902017-03-16 22:08:29 -0700152 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700153 ResourceId abs = ResourceIds.resourceId(parent, node);
154 //spath = ResourceIdParser.appendNodeKey(spath, node.key());
155 parseNode(ResourceIdParser.parseResId(abs), node);
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700156 return CompletableFuture.completedFuture(true);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800157 }
158
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700159 // FIXME this is more like addNode
160 /**
161 * @param path pointing to {@code node}
162 * @param node node
163 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800164 private void parseNode(String path, DataNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700165 log.trace("parseNode({}, {})", path, node);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700166 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800167 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400168 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800169 }
170 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
171 addLeaf(path, (LeafNode) node);
172 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700173 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800174 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400175 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800176 }
177 addLeaf(path, (LeafNode) node);
178 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
179 traverseInner(path, (InnerNode) node);
180 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700181 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800182 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400183 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800184 }
185 traverseInner(path, (InnerNode) node);
186 } else {
187 throw new FailedException("Invalid node type");
188 }
189 }
190
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700191 // FIXME this is more like addInnteNode
192 /**
193 * @param path pointing to {@code node}
194 * @param node node
195 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800196 private void traverseInner(String path, InnerNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700197 log.trace("traverseInner({}, {})", path, node);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800198 addKey(path, node.type());
199 Map<NodeKey, DataNode> entries = node.childNodes();
200 if (entries.size() == 0) {
Henry Yu5c54e772017-04-19 14:13:56 -0400201 return;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800202 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700203 // FIXME ignoring results
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800204 entries.forEach((k, v) -> {
205 String tempPath;
206 tempPath = ResourceIdParser.appendNodeKey(path, v.key());
207 if (v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
208 addLeaf(tempPath, (LeafNode) v);
209 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
210 tempPath = ResourceIdParser.appendLeafList(tempPath, (LeafListKey) v.key());
211 addLeaf(tempPath, (LeafNode) v);
212 } else if (v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
213 traverseInner(tempPath, (InnerNode) v);
214 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
215 tempPath = ResourceIdParser.appendKeyList(tempPath, (ListKey) v.key());
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700216 traverseInner(tempPath, (InnerNode) v);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800217 } else {
218 throw new FailedException("Invalid node type");
219 }
220 });
221 }
222
223 private Boolean addLeaf(String path, LeafNode node) {
224 objectStore.put(path, node);
225 return addKey(path, node.type());
226 }
227
228 private Boolean addKey(String path, DataNode.Type type) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700229 log.trace("addKey({}, {})", path, type);
230 DocumentPath dpath = DocumentPath.from(path);
231 log.trace("dpath={}", dpath);
232 // FIXME Not atomic, should probably use create or replace
233 if (completeVersioned(keystore.get(dpath)) != null) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700234 log.trace(" keystore.set({}, {})", dpath, type);
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700235 completeVersioned(keystore.set(dpath, type));
Sithara Punnasseryc70b7e52017-08-10 14:28:08 -0700236 return true;
237 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700238 log.trace(" keystore.create({}, {})", dpath, type);
239 Boolean result = complete(keystore.create(dpath, type));
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700240 return result;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800241 }
242
243 @Override
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800244 public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
245 CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800246 String spath = ResourceIdParser.parseResId(path);
247 DocumentPath dpath = DocumentPath.from(spath);
248 DataNode.Type type = null;
249 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
250 type = completeVersioned(ret);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800251 if (type == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700252 throw new FailedException("Requested node or some of the parents " +
253 "are not present in the requested path: " +
254 spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800255 }
256 DataNode retVal = null;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800257 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
258 retVal = readLeaf(spath);
259 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
260 retVal = readLeaf(spath);
261 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
262 NodeKey key = ResourceIdParser.getInstanceKey(path);
263 if (key == null) {
264 throw new FailedException("Key type did not match node type");
265 }
266 DataNode.Builder superBldr = InnerNode
267 .builder(key.schemaId().name(), key.schemaId().namespace())
268 .type(type);
269 readInner(superBldr, spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800270 retVal = superBldr.build();
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800271 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
272 NodeKey key = ResourceIdParser.getMultiInstanceKey(path);
273 if (key == null) {
274 throw new FailedException("Key type did not match node type");
275 }
276 DataNode.Builder superBldr = InnerNode
277 .builder(key.schemaId().name(), key.schemaId().namespace())
278 .type(type);
279 for (KeyLeaf keyLeaf : ((ListKey) key).keyLeafs()) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700280 //String tempPath = ResourceIdParser.appendKeyLeaf(spath, keyLeaf);
281 //LeafNode lfnd = readLeaf(tempPath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800282 superBldr.addKeyLeaf(keyLeaf.leafSchema().name(),
Henry Yu5c54e772017-04-19 14:13:56 -0400283 keyLeaf.leafSchema().namespace(), String.valueOf(keyLeaf.leafValue()));
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800284 }
285 readInner(superBldr, spath);
286 retVal = superBldr.build();
287 } else {
288 throw new FailedException("Invalid node type");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800289 }
290 if (retVal != null) {
291 eventFuture = CompletableFuture.completedFuture(retVal);
292 } else {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700293 log.info("STORE: Failed to READ node");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800294 }
295 return eventFuture;
296 }
297
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800298 private void readInner(DataNode.Builder superBldr, String spath) {
299 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
300 DocumentPath.from(spath));
301 Map<String, Versioned<DataNode.Type>> entries = null;
302 entries = complete(ret);
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700303 log.trace(" keystore.getChildren({})", spath);
304 log.trace(" entries keys:{}", entries.keySet());
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800305 if (!entries.isEmpty()) {
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700306 entries.forEach((k, v) -> {
307 String[] names = k.split(ResourceIdParser.NM_CHK);
308 String name = names[0];
309 String nmSpc = ResourceIdParser.getNamespace(names[1]);
310 String keyVal = ResourceIdParser.getKeyVal(names[1]);
311 DataNode.Type type = v.value();
312 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
313 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800314 LeafNode lfnode = readLeaf(tempPath);
315 // FIXME there should be builder for copying
316 superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700317 .type(type)
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800318 .leafType(lfnode.leafType())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700319 .exitNode();
320 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
321 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
322 LeafNode lfnode = readLeaf(mlpath);
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800323 // FIXME there should be builder for copying
324 superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700325 .type(type)
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800326 .leafType(lfnode.leafType())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700327 .addLeafListValue(lfnode.value())
328 .exitNode();
329 //TODO this alone should be sufficient and take the nm, nmspc too
330 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
331 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
332 .type(type);
333 readInner(tempBldr, tempPath);
334 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
335 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
336 .type(type);
337 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
338 String[] keys = k.split(ResourceIdParser.KEY_CHK);
339 for (int i = 1; i < keys.length; i++) {
340 //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
341 //LeafNode lfnd = readLeaf(curKey);
342 String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
343 tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
344 }
345 readInner(tempBldr, tempPath);
346 } else {
347 throw new FailedException("Invalid node type");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800348 }
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700349 });
350 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800351 superBldr.exitNode();
352 }
353
354 private LeafNode readLeaf(String path) {
355 return objectStore.get(path).value();
356 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700357
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700358 private void parseForUpdate(String path, DataNode node) {
359 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
360 addLeaf(path, (LeafNode) node);
361 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
362 path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
363 addLeaf(path, (LeafNode) node);
364 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
365 traverseInner(path, (InnerNode) node);
366 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
367 path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
368 traverseInner(path, (InnerNode) node);
369 } else {
370 throw new FailedException("Invalid node type");
371 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800372 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700373
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800374 @Override
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700375 public CompletableFuture<Boolean> updateNode(ResourceId complete, DataNode node) {
376 CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700377 String spath = ResourceIdParser.parseResId(complete);
378 if (spath == null) {
379 throw new FailedException("Invalid RsourceId, cannot update Node");
380 }
381 if (spath.compareTo(ResourceIdParser.ROOT) != 0) {
382 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
383 throw new FailedException("Node or parent doesnot exist, cannot update");
384 }
385 }
386 spath = ResourceIdParser.appendNodeKey(spath, node.key());
387 parseForUpdate(spath, node);
388 return eventFuture;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800389 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700390
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800391 @Override
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700392 public CompletableFuture<Boolean> nodeExist(ResourceId complete) {
393 Boolean stat = true;
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700394 String spath = ResourceIdParser.parseResId(complete);
395 if (spath == null) {
396 stat = false;
397 } else if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
398 stat = false;
399 }
400 return CompletableFuture.completedFuture(stat);
401 }
402
403 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800404 public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800405 throw new FailedException("Not yet implemented");
406 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700407
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800408 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800409 public CompletableFuture<Boolean> deleteNode(ResourceId path) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800410 throw new FailedException("Not yet implemented");
411 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800412
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700413 private void deleteInner(String spath) {
414 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
415 DocumentPath.from(spath));
416 Map<String, Versioned<DataNode.Type>> entries = null;
417 entries = complete(ret);
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700418 if ((entries != null) && (!entries.isEmpty())) {
419 entries.forEach((k, v) -> {
420 String[] names = k.split(ResourceIdParser.NM_CHK);
421 String name = names[0];
422 String nmSpc = ResourceIdParser.getNamespace(names[1]);
423 String keyVal = ResourceIdParser.getKeyVal(names[1]);
424 DataNode.Type type = v.value();
425 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
426 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
427 removeLeaf(tempPath);
428 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
429 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
430 removeLeaf(mlpath);
431 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
432 deleteInner(tempPath);
433 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
434 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
435 deleteInner(tempPath);
436 } else {
437 throw new FailedException("Invalid node type");
438 }
439 });
440 }
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700441 log.trace(" keystore.removeNode({})", spath);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700442 keystore.removeNode(DocumentPath.from(spath));
443 }
444
445 private void removeLeaf(String path) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700446 log.trace(" keystore.removeNode({})", path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700447 keystore.removeNode(DocumentPath.from(path));
448 objectStore.remove(path);
449 }
450
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800451 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800452 public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
453 String spath = ResourceIdParser.parseResId(path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700454 if (spath == null) {
Sithara Punnasserybc9edb12017-07-20 14:32:33 -0700455 throw new FailedException("Invalid RsourceId, cannot delete Node");
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700456 }
457 if (spath.compareTo(ResourceIdParser.ROOT) == 0) {
458 throw new FailedException("Cannot delete Root");
459 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800460 DocumentPath dpath = DocumentPath.from(spath);
461 DataNode.Type type = null;
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700462 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
463 type = completeVersioned(ret);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800464 if (type == null) {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700465 throw new FailedException("Cannot delete, Requested node or some of the parents" +
Henry Yu5c54e772017-04-19 14:13:56 -0400466 "are not present in the requested path");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800467 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700468 DataNode retVal = null;
469 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
470 removeLeaf(spath);
471 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
472 removeLeaf(spath);
473 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
474 deleteInner(spath);
475 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
476 deleteInner(spath);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800477 } else {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700478 throw new FailedException("Invalid node type");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800479 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700480 return CompletableFuture.completedFuture(true);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800481 }
482
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800483 public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
484 @Override
485 public void event(DocumentTreeEvent<DataNode.Type> event) {
486 DynamicConfigEvent.Type type;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800487 ResourceId path;
488 switch (event.type()) {
489 case CREATED:
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800490 type = NODE_ADDED;
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700491 //log.info("NODE added in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800492 break;
493 case UPDATED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700494 //log.info("NODE updated in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800495 type = NODE_UPDATED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800496 break;
497 case DELETED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700498 //log.info("NODE deleted in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800499 type = NODE_DELETED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800500 break;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800501 default:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700502 //log.info("UNKNOWN operation in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800503 type = UNKNOWN_OPRN;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800504 }
Yuta HIGUCHIdbc08c02018-02-12 16:40:05 -0800505 // FIXME don't use ResourceIdParser
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800506 path = ResourceIdParser.getResId(event.path().pathElements());
507 notifyDelegate(new DynamicConfigEvent(type, path));
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800508 }
509 }
510
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800511 public class InternalMapListener implements MapEventListener<String, LeafNode> {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800512 @Override
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800513 public void event(MapEvent<String, LeafNode> event) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800514 switch (event.type()) {
515 case INSERT:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800516 //log.info("NODE created in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800517 break;
518 case UPDATE:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800519 //log.info("NODE updated in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800520 break;
521 case REMOVE:
522 default:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800523 //log.info("NODE removed in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800524 break;
525 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800526 }
527 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800528
529 private <T> T complete(CompletableFuture<T> future) {
530 try {
531 return future.get();
532 } catch (InterruptedException e) {
533 Thread.currentThread().interrupt();
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700534 throw new FailedException(e.getCause().getMessage());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800535 } catch (ExecutionException e) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700536 if (e.getCause() instanceof IllegalDocumentModificationException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700537 throw new FailedException("Node or parent does not exist or is root or is not a Leaf Node",
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700538 e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800539 } else if (e.getCause() instanceof NoSuchDocumentPathException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700540 throw new FailedException("ResourceId does not exist", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800541 } else {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700542 throw new FailedException("Datastore operation failed", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800543 }
544 }
545 }
546
547 private <T> T completeVersioned(CompletableFuture<Versioned<T>> future) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700548 return Optional.ofNullable(complete(future))
549 .map(Versioned::value)
550 .orElse(null);
551 }
552}