blob: f74e26c10109818380947c370b147f2814808c97 [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;
Andrea Campanella2bdcb5f2018-08-27 11:20:34 +020032import org.onosproject.d.config.DeviceResourceIds;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070033import org.onosproject.d.config.ResourceIds;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080034import org.onosproject.store.AbstractStore;
35import org.onosproject.store.serializers.KryoNamespaces;
36import org.onosproject.store.service.AsyncDocumentTree;
37import org.onosproject.store.service.ConsistentMap;
38import org.onosproject.store.service.DocumentPath;
39import org.onosproject.store.service.DocumentTreeEvent;
40import org.onosproject.store.service.DocumentTreeListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080041import org.onosproject.store.service.IllegalDocumentModificationException;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080042import org.onosproject.store.service.MapEvent;
43import org.onosproject.store.service.MapEventListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080044import org.onosproject.store.service.NoSuchDocumentPathException;
Sithara Punnasserydb3591b2017-08-10 19:44:53 -070045import org.onosproject.store.service.Ordering;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080046import org.onosproject.store.service.Serializer;
47import org.onosproject.store.service.StorageService;
48import org.onosproject.store.service.Versioned;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080049import org.onosproject.yang.model.DataNode;
50import org.onosproject.yang.model.InnerNode;
51import org.onosproject.yang.model.KeyLeaf;
52import org.onosproject.yang.model.LeafListKey;
53import org.onosproject.yang.model.LeafNode;
Yuta HIGUCHIf662e312018-02-12 17:04:28 -080054import org.onosproject.yang.model.LeafType;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080055import org.onosproject.yang.model.ListKey;
56import org.onosproject.yang.model.NodeKey;
57import org.onosproject.yang.model.ResourceId;
58import org.onosproject.yang.model.SchemaId;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
Henry Yu5c54e772017-04-19 14:13:56 -040061
Gaurav Agrawalc3445a12017-11-16 20:37:58 +053062import java.math.BigDecimal;
Henry Yu5c54e772017-04-19 14:13:56 -040063import java.math.BigInteger;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070064import java.util.LinkedHashMap;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080065import java.util.Map;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070066import java.util.Optional;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080067import java.util.concurrent.CompletableFuture;
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080068import java.util.concurrent.ExecutionException;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080069import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080070import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
Henry Yu5c54e772017-04-19 14:13:56 -040071import static org.onosproject.config.DynamicConfigEvent.Type.NODE_UPDATED;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080072import static org.onosproject.config.DynamicConfigEvent.Type.UNKNOWN_OPRN;
Andrea Campanella2bdcb5f2018-08-27 11:20:34 +020073import static org.onosproject.d.config.DeviceResourceIds.DCS_NAMESPACE;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080074
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080075/**
76 * Implementation of the dynamic config store.
77 */
Sithara Punnassery06208792017-02-10 16:25:29 -080078@Beta
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080079@Component(immediate = true)
80@Service
81public class DistributedDynamicConfigStore
82 extends AbstractStore<DynamicConfigEvent, DynamicConfigStoreDelegate>
83 implements DynamicConfigStore {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070084
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080085 private final Logger log = LoggerFactory.getLogger(getClass());
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070086
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected StorageService storageService;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070089
90 // FIXME transactionally mutate the 2 or consolidate into 1 AsyncDocTree
91 // effectively tree structure only
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080092 private AsyncDocumentTree<DataNode.Type> keystore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070093 // TODO Can we pass DocumentPath directly to ConsistentMap?
94 // Map<DocumentPath as String, leaf value>
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080095 private ConsistentMap<String, LeafNode> objectStore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070096
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080097 private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080098 private final MapEventListener<String, LeafNode> olistener = new InternalMapListener();
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080099
100 @Activate
101 public void activateStore() {
102 KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
103 .register(KryoNamespaces.BASIC)
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700104 .register(Class.class)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800105 .register(DataNode.Type.class)
106 .register(LeafNode.class)
107 .register(InnerNode.class)
108 .register(ResourceId.class)
109 .register(NodeKey.class)
110 .register(SchemaId.class)
Sithara Punnassery43833e12017-03-14 16:29:19 -0700111 .register(LeafListKey.class)
112 .register(ListKey.class)
113 .register(KeyLeaf.class)
Henry Yu5c54e772017-04-19 14:13:56 -0400114 .register(BigInteger.class)
Gaurav Agrawalc3445a12017-11-16 20:37:58 +0530115 .register(BigDecimal.class)
Yuta HIGUCHIf662e312018-02-12 17:04:28 -0800116 .register(LinkedHashMap.class)
117 .register(LeafType.class);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800118 keystore = storageService.<DataNode.Type>documentTreeBuilder()
119 .withSerializer(Serializer.using(kryoBuilder.build()))
120 .withName("config-key-store")
121 .withRelaxedReadConsistency()
Sithara Punnasserydb3591b2017-08-10 19:44:53 -0700122 .withOrdering(Ordering.INSERTION)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800123 .buildDocumentTree();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800124 objectStore = storageService.<String, LeafNode>consistentMapBuilder()
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800125 .withSerializer(Serializer.using(kryoBuilder.build()))
126 .withName("config-object-store")
127 .withRelaxedReadConsistency()
128 .build();
129 keystore.addListener(klistener);
130 objectStore.addListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700131 log.info("Started");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800132 }
133
134 @Deactivate
135 public void deactivateStore() {
136 keystore.removeListener(klistener);
137 objectStore.removeListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700138 log.info("Stopped");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800139 }
140
141 @Override
142 public CompletableFuture<Boolean>
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700143 addNode(ResourceId parent, DataNode node) {
144 String spath = ResourceIdParser.parseResId(parent);
145 log.trace(" addNode({}, {})", parent, node);
146 log.trace(" spath={}", spath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800147 if (spath == null) {
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700148 throw new FailedException("Invalid ResourceId, cannot create Node");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800149 }
Jordan Haltermand4e94172018-08-21 10:38:43 -0700150 if (spath.equals(ResourceIdParser.ROOT)) {
Andrea Campanella2bdcb5f2018-08-27 11:20:34 +0200151 //If not present, adding static ROOT node after immutable documentTree root.
152 if (complete(keystore.get(DocumentPath.from(spath))) == null) {
153 addLeaf(spath, LeafNode.builder(DeviceResourceIds.ROOT_NAME, DCS_NAMESPACE)
154 .type(DataNode.Type.SINGLE_INSTANCE_NODE).build());
155 }
156 ResourceId abs = ResourceIds.resourceId(parent, node);
157 parseNode(ResourceIdParser.parseResId(abs), node);
Jordan Halterman686c8582018-07-31 18:19:33 -0700158 return CompletableFuture.completedFuture(true);
159 } else if (complete(keystore.get(DocumentPath.from(spath))) == null) {
160 throw new FailedException("Node or parent does not exist for " + spath);
Sithara Punnasserybb644902017-03-16 22:08:29 -0700161 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700162 ResourceId abs = ResourceIds.resourceId(parent, node);
163 //spath = ResourceIdParser.appendNodeKey(spath, node.key());
164 parseNode(ResourceIdParser.parseResId(abs), node);
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700165 return CompletableFuture.completedFuture(true);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800166 }
167
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700168 // FIXME this is more like addNode
169 /**
170 * @param path pointing to {@code node}
171 * @param node node
172 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800173 private void parseNode(String path, DataNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700174 log.trace("parseNode({}, {})", path, node);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700175 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800176 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400177 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800178 }
179 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
180 addLeaf(path, (LeafNode) node);
181 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700182 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800183 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400184 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800185 }
186 addLeaf(path, (LeafNode) node);
187 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
188 traverseInner(path, (InnerNode) node);
189 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700190 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800191 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400192 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800193 }
194 traverseInner(path, (InnerNode) node);
195 } else {
196 throw new FailedException("Invalid node type");
197 }
198 }
199
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700200 // FIXME this is more like addInnteNode
201 /**
202 * @param path pointing to {@code node}
203 * @param node node
204 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800205 private void traverseInner(String path, InnerNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700206 log.trace("traverseInner({}, {})", path, node);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800207 addKey(path, node.type());
208 Map<NodeKey, DataNode> entries = node.childNodes();
209 if (entries.size() == 0) {
Henry Yu5c54e772017-04-19 14:13:56 -0400210 return;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800211 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700212 // FIXME ignoring results
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800213 entries.forEach((k, v) -> {
214 String tempPath;
215 tempPath = ResourceIdParser.appendNodeKey(path, v.key());
216 if (v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
217 addLeaf(tempPath, (LeafNode) v);
218 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
219 tempPath = ResourceIdParser.appendLeafList(tempPath, (LeafListKey) v.key());
220 addLeaf(tempPath, (LeafNode) v);
221 } else if (v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
222 traverseInner(tempPath, (InnerNode) v);
223 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
224 tempPath = ResourceIdParser.appendKeyList(tempPath, (ListKey) v.key());
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700225 traverseInner(tempPath, (InnerNode) v);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800226 } else {
227 throw new FailedException("Invalid node type");
228 }
229 });
230 }
231
232 private Boolean addLeaf(String path, LeafNode node) {
233 objectStore.put(path, node);
234 return addKey(path, node.type());
235 }
236
237 private Boolean addKey(String path, DataNode.Type type) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700238 log.trace("addKey({}, {})", path, type);
239 DocumentPath dpath = DocumentPath.from(path);
240 log.trace("dpath={}", dpath);
241 // FIXME Not atomic, should probably use create or replace
242 if (completeVersioned(keystore.get(dpath)) != null) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700243 log.trace(" keystore.set({}, {})", dpath, type);
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700244 completeVersioned(keystore.set(dpath, type));
Sithara Punnasseryc70b7e52017-08-10 14:28:08 -0700245 return true;
246 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700247 log.trace(" keystore.create({}, {})", dpath, type);
248 Boolean result = complete(keystore.create(dpath, type));
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700249 return result;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800250 }
251
252 @Override
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800253 public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
254 CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800255 String spath = ResourceIdParser.parseResId(path);
256 DocumentPath dpath = DocumentPath.from(spath);
257 DataNode.Type type = null;
258 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
259 type = completeVersioned(ret);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800260 if (type == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700261 throw new FailedException("Requested node or some of the parents " +
262 "are not present in the requested path: " +
263 spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800264 }
265 DataNode retVal = null;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800266 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
267 retVal = readLeaf(spath);
268 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
269 retVal = readLeaf(spath);
270 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
271 NodeKey key = ResourceIdParser.getInstanceKey(path);
272 if (key == null) {
273 throw new FailedException("Key type did not match node type");
274 }
275 DataNode.Builder superBldr = InnerNode
276 .builder(key.schemaId().name(), key.schemaId().namespace())
277 .type(type);
278 readInner(superBldr, spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800279 retVal = superBldr.build();
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800280 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
281 NodeKey key = ResourceIdParser.getMultiInstanceKey(path);
282 if (key == null) {
283 throw new FailedException("Key type did not match node type");
284 }
285 DataNode.Builder superBldr = InnerNode
286 .builder(key.schemaId().name(), key.schemaId().namespace())
287 .type(type);
288 for (KeyLeaf keyLeaf : ((ListKey) key).keyLeafs()) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700289 //String tempPath = ResourceIdParser.appendKeyLeaf(spath, keyLeaf);
290 //LeafNode lfnd = readLeaf(tempPath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800291 superBldr.addKeyLeaf(keyLeaf.leafSchema().name(),
Henry Yu5c54e772017-04-19 14:13:56 -0400292 keyLeaf.leafSchema().namespace(), String.valueOf(keyLeaf.leafValue()));
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800293 }
294 readInner(superBldr, spath);
295 retVal = superBldr.build();
296 } else {
297 throw new FailedException("Invalid node type");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800298 }
299 if (retVal != null) {
300 eventFuture = CompletableFuture.completedFuture(retVal);
301 } else {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700302 log.info("STORE: Failed to READ node");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800303 }
304 return eventFuture;
305 }
306
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800307 private void readInner(DataNode.Builder superBldr, String spath) {
308 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
309 DocumentPath.from(spath));
310 Map<String, Versioned<DataNode.Type>> entries = null;
311 entries = complete(ret);
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700312 log.trace(" keystore.getChildren({})", spath);
313 log.trace(" entries keys:{}", entries.keySet());
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800314 if (!entries.isEmpty()) {
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700315 entries.forEach((k, v) -> {
316 String[] names = k.split(ResourceIdParser.NM_CHK);
317 String name = names[0];
318 String nmSpc = ResourceIdParser.getNamespace(names[1]);
319 String keyVal = ResourceIdParser.getKeyVal(names[1]);
320 DataNode.Type type = v.value();
321 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
322 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800323 LeafNode lfnode = readLeaf(tempPath);
324 // FIXME there should be builder for copying
325 superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700326 .type(type)
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800327 .leafType(lfnode.leafType())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700328 .exitNode();
329 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
330 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
331 LeafNode lfnode = readLeaf(mlpath);
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800332 // FIXME there should be builder for copying
333 superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700334 .type(type)
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800335 .leafType(lfnode.leafType())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700336 .addLeafListValue(lfnode.value())
337 .exitNode();
338 //TODO this alone should be sufficient and take the nm, nmspc too
339 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
340 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
341 .type(type);
342 readInner(tempBldr, tempPath);
343 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
344 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
345 .type(type);
346 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
347 String[] keys = k.split(ResourceIdParser.KEY_CHK);
348 for (int i = 1; i < keys.length; i++) {
349 //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
350 //LeafNode lfnd = readLeaf(curKey);
351 String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
352 tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
353 }
354 readInner(tempBldr, tempPath);
355 } else {
356 throw new FailedException("Invalid node type");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800357 }
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700358 });
359 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800360 superBldr.exitNode();
361 }
362
363 private LeafNode readLeaf(String path) {
364 return objectStore.get(path).value();
365 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700366
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700367 private void parseForUpdate(String path, DataNode node) {
368 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
369 addLeaf(path, (LeafNode) node);
370 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
371 path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
372 addLeaf(path, (LeafNode) node);
373 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
374 traverseInner(path, (InnerNode) node);
375 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
376 path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
377 traverseInner(path, (InnerNode) node);
378 } else {
379 throw new FailedException("Invalid node type");
380 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800381 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700382
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800383 @Override
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700384 public CompletableFuture<Boolean> updateNode(ResourceId complete, DataNode node) {
385 CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700386 String spath = ResourceIdParser.parseResId(complete);
387 if (spath == null) {
388 throw new FailedException("Invalid RsourceId, cannot update Node");
389 }
390 if (spath.compareTo(ResourceIdParser.ROOT) != 0) {
391 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
392 throw new FailedException("Node or parent doesnot exist, cannot update");
393 }
394 }
395 spath = ResourceIdParser.appendNodeKey(spath, node.key());
396 parseForUpdate(spath, node);
397 return eventFuture;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800398 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700399
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800400 @Override
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700401 public CompletableFuture<Boolean> nodeExist(ResourceId complete) {
402 Boolean stat = true;
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700403 String spath = ResourceIdParser.parseResId(complete);
404 if (spath == null) {
405 stat = false;
406 } else if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
407 stat = false;
408 }
409 return CompletableFuture.completedFuture(stat);
410 }
411
412 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800413 public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800414 throw new FailedException("Not yet implemented");
415 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700416
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800417 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800418 public CompletableFuture<Boolean> deleteNode(ResourceId path) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800419 throw new FailedException("Not yet implemented");
420 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800421
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700422 private void deleteInner(String spath) {
423 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
424 DocumentPath.from(spath));
425 Map<String, Versioned<DataNode.Type>> entries = null;
426 entries = complete(ret);
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700427 if ((entries != null) && (!entries.isEmpty())) {
428 entries.forEach((k, v) -> {
429 String[] names = k.split(ResourceIdParser.NM_CHK);
430 String name = names[0];
431 String nmSpc = ResourceIdParser.getNamespace(names[1]);
432 String keyVal = ResourceIdParser.getKeyVal(names[1]);
433 DataNode.Type type = v.value();
434 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
435 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
436 removeLeaf(tempPath);
437 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
438 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
439 removeLeaf(mlpath);
440 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
441 deleteInner(tempPath);
442 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
443 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
444 deleteInner(tempPath);
445 } else {
446 throw new FailedException("Invalid node type");
447 }
448 });
449 }
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700450 log.trace(" keystore.removeNode({})", spath);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700451 keystore.removeNode(DocumentPath.from(spath));
452 }
453
454 private void removeLeaf(String path) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700455 log.trace(" keystore.removeNode({})", path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700456 keystore.removeNode(DocumentPath.from(path));
457 objectStore.remove(path);
458 }
459
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800460 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800461 public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
462 String spath = ResourceIdParser.parseResId(path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700463 if (spath == null) {
Sithara Punnasserybc9edb12017-07-20 14:32:33 -0700464 throw new FailedException("Invalid RsourceId, cannot delete Node");
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700465 }
466 if (spath.compareTo(ResourceIdParser.ROOT) == 0) {
467 throw new FailedException("Cannot delete Root");
468 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800469 DocumentPath dpath = DocumentPath.from(spath);
470 DataNode.Type type = null;
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700471 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
472 type = completeVersioned(ret);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800473 if (type == null) {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700474 throw new FailedException("Cannot delete, Requested node or some of the parents" +
Henry Yu5c54e772017-04-19 14:13:56 -0400475 "are not present in the requested path");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800476 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700477 DataNode retVal = null;
478 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
479 removeLeaf(spath);
480 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
481 removeLeaf(spath);
482 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
483 deleteInner(spath);
484 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
485 deleteInner(spath);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800486 } else {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700487 throw new FailedException("Invalid node type");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800488 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700489 return CompletableFuture.completedFuture(true);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800490 }
491
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800492 public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
493 @Override
494 public void event(DocumentTreeEvent<DataNode.Type> event) {
495 DynamicConfigEvent.Type type;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800496 ResourceId path;
497 switch (event.type()) {
498 case CREATED:
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800499 type = NODE_ADDED;
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700500 //log.info("NODE added in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800501 break;
502 case UPDATED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700503 //log.info("NODE updated in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800504 type = NODE_UPDATED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800505 break;
506 case DELETED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700507 //log.info("NODE deleted in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800508 type = NODE_DELETED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800509 break;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800510 default:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700511 //log.info("UNKNOWN operation in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800512 type = UNKNOWN_OPRN;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800513 }
Yuta HIGUCHIdbc08c02018-02-12 16:40:05 -0800514 // FIXME don't use ResourceIdParser
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800515 path = ResourceIdParser.getResId(event.path().pathElements());
516 notifyDelegate(new DynamicConfigEvent(type, path));
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800517 }
518 }
519
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800520 public class InternalMapListener implements MapEventListener<String, LeafNode> {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800521 @Override
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800522 public void event(MapEvent<String, LeafNode> event) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800523 switch (event.type()) {
524 case INSERT:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800525 //log.info("NODE created in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800526 break;
527 case UPDATE:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800528 //log.info("NODE updated in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800529 break;
530 case REMOVE:
531 default:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800532 //log.info("NODE removed in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800533 break;
534 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800535 }
536 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800537
538 private <T> T complete(CompletableFuture<T> future) {
539 try {
540 return future.get();
541 } catch (InterruptedException e) {
542 Thread.currentThread().interrupt();
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700543 throw new FailedException(e.getCause().getMessage());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800544 } catch (ExecutionException e) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700545 if (e.getCause() instanceof IllegalDocumentModificationException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700546 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 -0700547 e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800548 } else if (e.getCause() instanceof NoSuchDocumentPathException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700549 throw new FailedException("ResourceId does not exist", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800550 } else {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700551 throw new FailedException("Datastore operation failed", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800552 }
553 }
554 }
555
556 private <T> T completeVersioned(CompletableFuture<Versioned<T>> future) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700557 return Optional.ofNullable(complete(future))
558 .map(Versioned::value)
559 .orElse(null);
560 }
561}