blob: b7ae3306131133f8f6b2a705cb33c216b7787603 [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;
53import org.onosproject.yang.model.ListKey;
54import org.onosproject.yang.model.NodeKey;
55import org.onosproject.yang.model.ResourceId;
56import org.onosproject.yang.model.SchemaId;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
Henry Yu5c54e772017-04-19 14:13:56 -040059
60import java.math.BigInteger;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070061import java.util.LinkedHashMap;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080062import java.util.Map;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070063import java.util.Optional;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080064import java.util.concurrent.CompletableFuture;
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080065import java.util.concurrent.ExecutionException;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080066import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080067import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
Henry Yu5c54e772017-04-19 14:13:56 -040068import static org.onosproject.config.DynamicConfigEvent.Type.NODE_UPDATED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080069import static org.onosproject.config.DynamicConfigEvent.Type.UNKNOWN_OPRN;
70
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080071/**
72 * Implementation of the dynamic config store.
73 */
Sithara Punnassery06208792017-02-10 16:25:29 -080074@Beta
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080075@Component(immediate = true)
76@Service
77public class DistributedDynamicConfigStore
78 extends AbstractStore<DynamicConfigEvent, DynamicConfigStoreDelegate>
79 implements DynamicConfigStore {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070080
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080081 private final Logger log = LoggerFactory.getLogger(getClass());
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070082
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080083 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected StorageService storageService;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070085
86 // FIXME transactionally mutate the 2 or consolidate into 1 AsyncDocTree
87 // effectively tree structure only
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080088 private AsyncDocumentTree<DataNode.Type> keystore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070089 // TODO Can we pass DocumentPath directly to ConsistentMap?
90 // Map<DocumentPath as String, leaf value>
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080091 private ConsistentMap<String, LeafNode> objectStore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070092
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080093 private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080094 private final MapEventListener<String, LeafNode> olistener = new InternalMapListener();
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080095
96 @Activate
97 public void activateStore() {
98 KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
99 .register(KryoNamespaces.BASIC)
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700100 .register(Class.class)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800101 .register(DataNode.Type.class)
102 .register(LeafNode.class)
103 .register(InnerNode.class)
104 .register(ResourceId.class)
105 .register(NodeKey.class)
106 .register(SchemaId.class)
Sithara Punnassery43833e12017-03-14 16:29:19 -0700107 .register(LeafListKey.class)
108 .register(ListKey.class)
109 .register(KeyLeaf.class)
Henry Yu5c54e772017-04-19 14:13:56 -0400110 .register(BigInteger.class)
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700111 .register(LinkedHashMap.class);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800112 keystore = storageService.<DataNode.Type>documentTreeBuilder()
113 .withSerializer(Serializer.using(kryoBuilder.build()))
114 .withName("config-key-store")
115 .withRelaxedReadConsistency()
Sithara Punnasserydb3591b2017-08-10 19:44:53 -0700116 .withOrdering(Ordering.INSERTION)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800117 .buildDocumentTree();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800118 objectStore = storageService.<String, LeafNode>consistentMapBuilder()
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800119 .withSerializer(Serializer.using(kryoBuilder.build()))
120 .withName("config-object-store")
121 .withRelaxedReadConsistency()
122 .build();
123 keystore.addListener(klistener);
124 objectStore.addListener(olistener);
125 log.info("DyanmicConfig Store Active");
126 }
127
128 @Deactivate
129 public void deactivateStore() {
130 keystore.removeListener(klistener);
131 objectStore.removeListener(olistener);
132 log.info("DyanmicConfig Store Stopped");
133 }
134
135 @Override
136 public CompletableFuture<Boolean>
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700137 addNode(ResourceId parent, DataNode node) {
138 String spath = ResourceIdParser.parseResId(parent);
139 log.trace(" addNode({}, {})", parent, node);
140 log.trace(" spath={}", spath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800141 if (spath == null) {
142 throw new FailedException("Invalid RsourceId, cannot create Node");
143 }
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700144 if (!spath.equals(ResourceIdParser.ROOT)) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700145 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700146 throw new FailedException("Node or parent does not exist for " + spath);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700147 }
Sithara Punnasserybb644902017-03-16 22:08:29 -0700148 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700149 ResourceId abs = ResourceIds.resourceId(parent, node);
150 //spath = ResourceIdParser.appendNodeKey(spath, node.key());
151 parseNode(ResourceIdParser.parseResId(abs), node);
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700152 return CompletableFuture.completedFuture(true);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800153 }
154
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700155 // FIXME this is more like addNode
156 /**
157 * @param path pointing to {@code node}
158 * @param node node
159 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800160 private void parseNode(String path, DataNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700161 log.trace("parseNode({}, {})", path, node);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700162 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800163 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400164 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800165 }
166 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
167 addLeaf(path, (LeafNode) node);
168 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700169 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800170 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400171 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800172 }
173 addLeaf(path, (LeafNode) node);
174 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
175 traverseInner(path, (InnerNode) node);
176 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700177 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800178 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400179 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800180 }
181 traverseInner(path, (InnerNode) node);
182 } else {
183 throw new FailedException("Invalid node type");
184 }
185 }
186
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700187 // FIXME this is more like addInnteNode
188 /**
189 * @param path pointing to {@code node}
190 * @param node node
191 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800192 private void traverseInner(String path, InnerNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700193 log.trace("traverseInner({}, {})", path, node);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800194 addKey(path, node.type());
195 Map<NodeKey, DataNode> entries = node.childNodes();
196 if (entries.size() == 0) {
Henry Yu5c54e772017-04-19 14:13:56 -0400197 return;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800198 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700199 // FIXME ignoring results
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800200 entries.forEach((k, v) -> {
201 String tempPath;
202 tempPath = ResourceIdParser.appendNodeKey(path, v.key());
203 if (v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
204 addLeaf(tempPath, (LeafNode) v);
205 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
206 tempPath = ResourceIdParser.appendLeafList(tempPath, (LeafListKey) v.key());
207 addLeaf(tempPath, (LeafNode) v);
208 } else if (v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
209 traverseInner(tempPath, (InnerNode) v);
210 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
211 tempPath = ResourceIdParser.appendKeyList(tempPath, (ListKey) v.key());
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700212 traverseInner(tempPath, (InnerNode) v);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800213 } else {
214 throw new FailedException("Invalid node type");
215 }
216 });
217 }
218
219 private Boolean addLeaf(String path, LeafNode node) {
220 objectStore.put(path, node);
221 return addKey(path, node.type());
222 }
223
224 private Boolean addKey(String path, DataNode.Type type) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700225 log.trace("addKey({}, {})", path, type);
226 DocumentPath dpath = DocumentPath.from(path);
227 log.trace("dpath={}", dpath);
228 // FIXME Not atomic, should probably use create or replace
229 if (completeVersioned(keystore.get(dpath)) != null) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700230 log.trace(" keystore.set({}, {})", dpath, type);
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700231 completeVersioned(keystore.set(dpath, type));
Sithara Punnasseryc70b7e52017-08-10 14:28:08 -0700232 return true;
233 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700234 log.trace(" keystore.create({}, {})", dpath, type);
235 Boolean result = complete(keystore.create(dpath, type));
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700236 return result;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800237 }
238
239 @Override
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800240 public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
241 CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800242 String spath = ResourceIdParser.parseResId(path);
243 DocumentPath dpath = DocumentPath.from(spath);
244 DataNode.Type type = null;
245 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
246 type = completeVersioned(ret);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800247 if (type == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700248 throw new FailedException("Requested node or some of the parents " +
249 "are not present in the requested path: " +
250 spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800251 }
252 DataNode retVal = null;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800253 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
254 retVal = readLeaf(spath);
255 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
256 retVal = readLeaf(spath);
257 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
258 NodeKey key = ResourceIdParser.getInstanceKey(path);
259 if (key == null) {
260 throw new FailedException("Key type did not match node type");
261 }
262 DataNode.Builder superBldr = InnerNode
263 .builder(key.schemaId().name(), key.schemaId().namespace())
264 .type(type);
265 readInner(superBldr, spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800266 retVal = superBldr.build();
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800267 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
268 NodeKey key = ResourceIdParser.getMultiInstanceKey(path);
269 if (key == null) {
270 throw new FailedException("Key type did not match node type");
271 }
272 DataNode.Builder superBldr = InnerNode
273 .builder(key.schemaId().name(), key.schemaId().namespace())
274 .type(type);
275 for (KeyLeaf keyLeaf : ((ListKey) key).keyLeafs()) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700276 //String tempPath = ResourceIdParser.appendKeyLeaf(spath, keyLeaf);
277 //LeafNode lfnd = readLeaf(tempPath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800278 superBldr.addKeyLeaf(keyLeaf.leafSchema().name(),
Henry Yu5c54e772017-04-19 14:13:56 -0400279 keyLeaf.leafSchema().namespace(), String.valueOf(keyLeaf.leafValue()));
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800280 }
281 readInner(superBldr, spath);
282 retVal = superBldr.build();
283 } else {
284 throw new FailedException("Invalid node type");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800285 }
286 if (retVal != null) {
287 eventFuture = CompletableFuture.completedFuture(retVal);
288 } else {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700289 log.info("STORE: Failed to READ node");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800290 }
291 return eventFuture;
292 }
293
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800294 private void readInner(DataNode.Builder superBldr, String spath) {
295 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
296 DocumentPath.from(spath));
297 Map<String, Versioned<DataNode.Type>> entries = null;
298 entries = complete(ret);
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700299 log.trace(" keystore.getChildren({})", spath);
300 log.trace(" entries keys:{}", entries.keySet());
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700301 if ((entries != null) && (!entries.isEmpty())) {
302 entries.forEach((k, v) -> {
303 String[] names = k.split(ResourceIdParser.NM_CHK);
304 String name = names[0];
305 String nmSpc = ResourceIdParser.getNamespace(names[1]);
306 String keyVal = ResourceIdParser.getKeyVal(names[1]);
307 DataNode.Type type = v.value();
308 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
309 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
310 superBldr.createChildBuilder(name, nmSpc, readLeaf(tempPath).value())
311 .type(type)
312 .exitNode();
313 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
314 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
315 LeafNode lfnode = readLeaf(mlpath);
316 superBldr.createChildBuilder(name, nmSpc, lfnode.value())
317 .type(type)
318 .addLeafListValue(lfnode.value())
319 .exitNode();
320 //TODO this alone should be sufficient and take the nm, nmspc too
321 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
322 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
323 .type(type);
324 readInner(tempBldr, tempPath);
325 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
326 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
327 .type(type);
328 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
329 String[] keys = k.split(ResourceIdParser.KEY_CHK);
330 for (int i = 1; i < keys.length; i++) {
331 //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
332 //LeafNode lfnd = readLeaf(curKey);
333 String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
334 tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
335 }
336 readInner(tempBldr, tempPath);
337 } else {
338 throw new FailedException("Invalid node type");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800339 }
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700340 });
341 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800342 superBldr.exitNode();
343 }
344
345 private LeafNode readLeaf(String path) {
346 return objectStore.get(path).value();
347 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700348
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700349 private void parseForUpdate(String path, DataNode node) {
350 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
351 addLeaf(path, (LeafNode) node);
352 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
353 path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
354 addLeaf(path, (LeafNode) node);
355 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
356 traverseInner(path, (InnerNode) node);
357 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
358 path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
359 traverseInner(path, (InnerNode) node);
360 } else {
361 throw new FailedException("Invalid node type");
362 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800363 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700364
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800365 @Override
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700366 public CompletableFuture<Boolean> updateNode(ResourceId complete, DataNode node) {
367 CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700368 String spath = ResourceIdParser.parseResId(complete);
369 if (spath == null) {
370 throw new FailedException("Invalid RsourceId, cannot update Node");
371 }
372 if (spath.compareTo(ResourceIdParser.ROOT) != 0) {
373 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
374 throw new FailedException("Node or parent doesnot exist, cannot update");
375 }
376 }
377 spath = ResourceIdParser.appendNodeKey(spath, node.key());
378 parseForUpdate(spath, node);
379 return eventFuture;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800380 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700381
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800382 @Override
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700383 public CompletableFuture<Boolean> nodeExist(ResourceId complete) {
384 Boolean stat = true;
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700385 String spath = ResourceIdParser.parseResId(complete);
386 if (spath == null) {
387 stat = false;
388 } else if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
389 stat = false;
390 }
391 return CompletableFuture.completedFuture(stat);
392 }
393
394 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800395 public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800396 throw new FailedException("Not yet implemented");
397 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700398
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800399 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800400 public CompletableFuture<Boolean> deleteNode(ResourceId path) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800401 throw new FailedException("Not yet implemented");
402 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800403
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700404 private void deleteInner(String spath) {
405 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
406 DocumentPath.from(spath));
407 Map<String, Versioned<DataNode.Type>> entries = null;
408 entries = complete(ret);
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700409 if ((entries != null) && (!entries.isEmpty())) {
410 entries.forEach((k, v) -> {
411 String[] names = k.split(ResourceIdParser.NM_CHK);
412 String name = names[0];
413 String nmSpc = ResourceIdParser.getNamespace(names[1]);
414 String keyVal = ResourceIdParser.getKeyVal(names[1]);
415 DataNode.Type type = v.value();
416 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
417 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
418 removeLeaf(tempPath);
419 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
420 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
421 removeLeaf(mlpath);
422 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
423 deleteInner(tempPath);
424 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
425 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
426 deleteInner(tempPath);
427 } else {
428 throw new FailedException("Invalid node type");
429 }
430 });
431 }
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700432 log.trace(" keystore.removeNode({})", spath);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700433 keystore.removeNode(DocumentPath.from(spath));
434 }
435
436 private void removeLeaf(String path) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700437 log.trace(" keystore.removeNode({})", path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700438 keystore.removeNode(DocumentPath.from(path));
439 objectStore.remove(path);
440 }
441
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800442 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800443 public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
444 String spath = ResourceIdParser.parseResId(path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700445 if (spath == null) {
Sithara Punnasserybc9edb12017-07-20 14:32:33 -0700446 throw new FailedException("Invalid RsourceId, cannot delete Node");
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700447 }
448 if (spath.compareTo(ResourceIdParser.ROOT) == 0) {
449 throw new FailedException("Cannot delete Root");
450 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800451 DocumentPath dpath = DocumentPath.from(spath);
452 DataNode.Type type = null;
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700453 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
454 type = completeVersioned(ret);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800455 if (type == null) {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700456 throw new FailedException("Cannot delete, Requested node or some of the parents" +
Henry Yu5c54e772017-04-19 14:13:56 -0400457 "are not present in the requested path");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800458 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700459 DataNode retVal = null;
460 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
461 removeLeaf(spath);
462 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
463 removeLeaf(spath);
464 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
465 deleteInner(spath);
466 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
467 deleteInner(spath);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800468 } else {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700469 throw new FailedException("Invalid node type");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800470 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700471 return CompletableFuture.completedFuture(true);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800472 }
473
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800474 public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
475 @Override
476 public void event(DocumentTreeEvent<DataNode.Type> event) {
477 DynamicConfigEvent.Type type;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800478 ResourceId path;
479 switch (event.type()) {
480 case CREATED:
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800481 type = NODE_ADDED;
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700482 //log.info("NODE added in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800483 break;
484 case UPDATED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700485 //log.info("NODE updated in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800486 type = NODE_UPDATED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800487 break;
488 case DELETED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700489 //log.info("NODE deleted in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800490 type = NODE_DELETED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800491 break;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800492 default:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700493 //log.info("UNKNOWN operation in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800494 type = UNKNOWN_OPRN;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800495 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800496 path = ResourceIdParser.getResId(event.path().pathElements());
497 notifyDelegate(new DynamicConfigEvent(type, path));
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800498 }
499 }
500
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800501 public class InternalMapListener implements MapEventListener<String, LeafNode> {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800502 @Override
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800503 public void event(MapEvent<String, LeafNode> event) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800504 switch (event.type()) {
505 case INSERT:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800506 //log.info("NODE created in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800507 break;
508 case UPDATE:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800509 //log.info("NODE updated in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800510 break;
511 case REMOVE:
512 default:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800513 //log.info("NODE removed in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800514 break;
515 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800516 }
517 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800518
519 private <T> T complete(CompletableFuture<T> future) {
520 try {
521 return future.get();
522 } catch (InterruptedException e) {
523 Thread.currentThread().interrupt();
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700524 throw new FailedException(e.getCause().getMessage());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800525 } catch (ExecutionException e) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700526 if (e.getCause() instanceof IllegalDocumentModificationException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700527 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 -0700528 e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800529 } else if (e.getCause() instanceof NoSuchDocumentPathException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700530 throw new FailedException("ResourceId does not exist", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800531 } else {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700532 throw new FailedException("Datastore operation failed", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800533 }
534 }
535 }
536
537 private <T> T completeVersioned(CompletableFuture<Versioned<T>> future) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700538 return Optional.ofNullable(complete(future))
539 .map(Versioned::value)
540 .orElse(null);
541 }
542}