blob: 62cd86da25259ee3a6bd77ac412225635f319ebb [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.onlab.util.KryoNamespace;
20import org.onosproject.config.DynamicConfigEvent;
21import org.onosproject.config.DynamicConfigStore;
22import org.onosproject.config.DynamicConfigStoreDelegate;
23import org.onosproject.config.FailedException;
24import org.onosproject.config.Filter;
Henry Yu5c54e772017-04-19 14:13:56 -040025import org.onosproject.config.ResourceIdParser;
Andrea Campanella2bdcb5f2018-08-27 11:20:34 +020026import org.onosproject.d.config.DeviceResourceIds;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070027import org.onosproject.d.config.ResourceIds;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080028import org.onosproject.store.AbstractStore;
29import org.onosproject.store.serializers.KryoNamespaces;
30import org.onosproject.store.service.AsyncDocumentTree;
31import org.onosproject.store.service.ConsistentMap;
32import org.onosproject.store.service.DocumentPath;
33import org.onosproject.store.service.DocumentTreeEvent;
34import org.onosproject.store.service.DocumentTreeListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080035import org.onosproject.store.service.IllegalDocumentModificationException;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080036import org.onosproject.store.service.MapEvent;
37import org.onosproject.store.service.MapEventListener;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080038import org.onosproject.store.service.NoSuchDocumentPathException;
Sithara Punnasserydb3591b2017-08-10 19:44:53 -070039import org.onosproject.store.service.Ordering;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080040import org.onosproject.store.service.Serializer;
41import org.onosproject.store.service.StorageService;
42import org.onosproject.store.service.Versioned;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080043import org.onosproject.yang.model.DataNode;
44import org.onosproject.yang.model.InnerNode;
45import org.onosproject.yang.model.KeyLeaf;
46import org.onosproject.yang.model.LeafListKey;
47import org.onosproject.yang.model.LeafNode;
Yuta HIGUCHIf662e312018-02-12 17:04:28 -080048import org.onosproject.yang.model.LeafType;
Sithara Punnassery44e2a702017-03-06 15:38:10 -080049import org.onosproject.yang.model.ListKey;
50import org.onosproject.yang.model.NodeKey;
51import org.onosproject.yang.model.ResourceId;
52import org.onosproject.yang.model.SchemaId;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070053import org.osgi.service.component.annotations.Activate;
54import org.osgi.service.component.annotations.Component;
55import org.osgi.service.component.annotations.Deactivate;
56import org.osgi.service.component.annotations.Reference;
57import org.osgi.service.component.annotations.ReferenceCardinality;
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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068
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
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079@Component(immediate = true, service = DynamicConfigStore.class)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080080public class DistributedDynamicConfigStore
81 extends AbstractStore<DynamicConfigEvent, DynamicConfigStoreDelegate>
82 implements DynamicConfigStore {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070083
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080084 private final Logger log = LoggerFactory.getLogger(getClass());
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070085
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080087 protected StorageService storageService;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070088
89 // FIXME transactionally mutate the 2 or consolidate into 1 AsyncDocTree
90 // effectively tree structure only
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080091 private AsyncDocumentTree<DataNode.Type> keystore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070092 // TODO Can we pass DocumentPath directly to ConsistentMap?
93 // Map<DocumentPath as String, leaf value>
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080094 private ConsistentMap<String, LeafNode> objectStore;
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -070095
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080096 private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -080097 private final MapEventListener<String, LeafNode> olistener = new InternalMapListener();
Sithara Punnassery9306e6b2017-02-06 15:38:19 -080098
99 @Activate
100 public void activateStore() {
101 KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
102 .register(KryoNamespaces.BASIC)
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700103 .register(Class.class)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800104 .register(DataNode.Type.class)
105 .register(LeafNode.class)
106 .register(InnerNode.class)
107 .register(ResourceId.class)
108 .register(NodeKey.class)
109 .register(SchemaId.class)
Sithara Punnassery43833e12017-03-14 16:29:19 -0700110 .register(LeafListKey.class)
111 .register(ListKey.class)
112 .register(KeyLeaf.class)
Henry Yu5c54e772017-04-19 14:13:56 -0400113 .register(BigInteger.class)
Gaurav Agrawalc3445a12017-11-16 20:37:58 +0530114 .register(BigDecimal.class)
Yuta HIGUCHIf662e312018-02-12 17:04:28 -0800115 .register(LinkedHashMap.class)
116 .register(LeafType.class);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800117 keystore = storageService.<DataNode.Type>documentTreeBuilder()
118 .withSerializer(Serializer.using(kryoBuilder.build()))
119 .withName("config-key-store")
120 .withRelaxedReadConsistency()
Sithara Punnasserydb3591b2017-08-10 19:44:53 -0700121 .withOrdering(Ordering.INSERTION)
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800122 .buildDocumentTree();
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800123 objectStore = storageService.<String, LeafNode>consistentMapBuilder()
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800124 .withSerializer(Serializer.using(kryoBuilder.build()))
125 .withName("config-object-store")
126 .withRelaxedReadConsistency()
127 .build();
128 keystore.addListener(klistener);
129 objectStore.addListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700130 log.info("Started");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800131 }
132
133 @Deactivate
134 public void deactivateStore() {
135 keystore.removeListener(klistener);
136 objectStore.removeListener(olistener);
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700137 log.info("Stopped");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800138 }
139
140 @Override
141 public CompletableFuture<Boolean>
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700142 addNode(ResourceId parent, DataNode node) {
143 String spath = ResourceIdParser.parseResId(parent);
144 log.trace(" addNode({}, {})", parent, node);
145 log.trace(" spath={}", spath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800146 if (spath == null) {
Yuta HIGUCHI289f45c2017-11-01 17:49:45 -0700147 throw new FailedException("Invalid ResourceId, cannot create Node");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800148 }
Jordan Haltermand4e94172018-08-21 10:38:43 -0700149 if (spath.equals(ResourceIdParser.ROOT)) {
Andrea Campanella2bdcb5f2018-08-27 11:20:34 +0200150 //If not present, adding static ROOT node after immutable documentTree root.
151 if (complete(keystore.get(DocumentPath.from(spath))) == null) {
152 addLeaf(spath, LeafNode.builder(DeviceResourceIds.ROOT_NAME, DCS_NAMESPACE)
153 .type(DataNode.Type.SINGLE_INSTANCE_NODE).build());
154 }
155 ResourceId abs = ResourceIds.resourceId(parent, node);
156 parseNode(ResourceIdParser.parseResId(abs), node);
Jordan Halterman686c8582018-07-31 18:19:33 -0700157 return CompletableFuture.completedFuture(true);
158 } else if (complete(keystore.get(DocumentPath.from(spath))) == null) {
159 throw new FailedException("Node or parent does not exist for " + spath);
Sithara Punnasserybb644902017-03-16 22:08:29 -0700160 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700161 ResourceId abs = ResourceIds.resourceId(parent, node);
162 //spath = ResourceIdParser.appendNodeKey(spath, node.key());
163 parseNode(ResourceIdParser.parseResId(abs), node);
Yuta HIGUCHI153d3582017-09-01 16:59:52 -0700164 return CompletableFuture.completedFuture(true);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800165 }
166
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700167 // FIXME this is more like addNode
168 /**
169 * @param path pointing to {@code node}
170 * @param node node
171 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800172 private void parseNode(String path, DataNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700173 log.trace("parseNode({}, {})", path, node);
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700174 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800175 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400176 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800177 }
178 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
179 addLeaf(path, (LeafNode) node);
180 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_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 addLeaf(path, (LeafNode) node);
186 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
187 traverseInner(path, (InnerNode) node);
188 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700189 if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800190 throw new FailedException("Requested node already present in the" +
Henry Yu5c54e772017-04-19 14:13:56 -0400191 " store, please use an update method");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800192 }
193 traverseInner(path, (InnerNode) node);
194 } else {
195 throw new FailedException("Invalid node type");
196 }
197 }
198
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700199 // FIXME this is more like addInnteNode
200 /**
201 * @param path pointing to {@code node}
202 * @param node node
203 */
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800204 private void traverseInner(String path, InnerNode node) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700205 log.trace("traverseInner({}, {})", path, node);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800206 addKey(path, node.type());
207 Map<NodeKey, DataNode> entries = node.childNodes();
208 if (entries.size() == 0) {
Henry Yu5c54e772017-04-19 14:13:56 -0400209 return;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800210 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700211 // FIXME ignoring results
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800212 entries.forEach((k, v) -> {
213 String tempPath;
214 tempPath = ResourceIdParser.appendNodeKey(path, v.key());
215 if (v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
216 addLeaf(tempPath, (LeafNode) v);
217 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
218 tempPath = ResourceIdParser.appendLeafList(tempPath, (LeafListKey) v.key());
219 addLeaf(tempPath, (LeafNode) v);
220 } else if (v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
221 traverseInner(tempPath, (InnerNode) v);
222 } else if (v.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
223 tempPath = ResourceIdParser.appendKeyList(tempPath, (ListKey) v.key());
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700224 traverseInner(tempPath, (InnerNode) v);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800225 } else {
226 throw new FailedException("Invalid node type");
227 }
228 });
229 }
230
231 private Boolean addLeaf(String path, LeafNode node) {
232 objectStore.put(path, node);
233 return addKey(path, node.type());
234 }
235
236 private Boolean addKey(String path, DataNode.Type type) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700237 log.trace("addKey({}, {})", path, type);
238 DocumentPath dpath = DocumentPath.from(path);
239 log.trace("dpath={}", dpath);
240 // FIXME Not atomic, should probably use create or replace
241 if (completeVersioned(keystore.get(dpath)) != null) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700242 log.trace(" keystore.set({}, {})", dpath, type);
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700243 completeVersioned(keystore.set(dpath, type));
Sithara Punnasseryc70b7e52017-08-10 14:28:08 -0700244 return true;
245 }
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700246 log.trace(" keystore.create({}, {})", dpath, type);
247 Boolean result = complete(keystore.create(dpath, type));
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700248 return result;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800249 }
250
251 @Override
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800252 public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
253 CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800254 String spath = ResourceIdParser.parseResId(path);
255 DocumentPath dpath = DocumentPath.from(spath);
256 DataNode.Type type = null;
257 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
258 type = completeVersioned(ret);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800259 if (type == null) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700260 throw new FailedException("Requested node or some of the parents " +
261 "are not present in the requested path: " +
262 spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800263 }
264 DataNode retVal = null;
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800265 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
266 retVal = readLeaf(spath);
267 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
268 retVal = readLeaf(spath);
269 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
270 NodeKey key = ResourceIdParser.getInstanceKey(path);
271 if (key == null) {
272 throw new FailedException("Key type did not match node type");
273 }
274 DataNode.Builder superBldr = InnerNode
275 .builder(key.schemaId().name(), key.schemaId().namespace())
276 .type(type);
277 readInner(superBldr, spath);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800278 retVal = superBldr.build();
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800279 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
280 NodeKey key = ResourceIdParser.getMultiInstanceKey(path);
281 if (key == null) {
282 throw new FailedException("Key type did not match node type");
283 }
284 DataNode.Builder superBldr = InnerNode
285 .builder(key.schemaId().name(), key.schemaId().namespace())
286 .type(type);
287 for (KeyLeaf keyLeaf : ((ListKey) key).keyLeafs()) {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700288 //String tempPath = ResourceIdParser.appendKeyLeaf(spath, keyLeaf);
289 //LeafNode lfnd = readLeaf(tempPath);
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800290 superBldr.addKeyLeaf(keyLeaf.leafSchema().name(),
Henry Yu5c54e772017-04-19 14:13:56 -0400291 keyLeaf.leafSchema().namespace(), String.valueOf(keyLeaf.leafValue()));
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800292 }
293 readInner(superBldr, spath);
294 retVal = superBldr.build();
295 } else {
296 throw new FailedException("Invalid node type");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800297 }
298 if (retVal != null) {
299 eventFuture = CompletableFuture.completedFuture(retVal);
300 } else {
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700301 log.info("STORE: Failed to READ node");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800302 }
303 return eventFuture;
304 }
305
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800306 private void readInner(DataNode.Builder superBldr, String spath) {
307 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
308 DocumentPath.from(spath));
309 Map<String, Versioned<DataNode.Type>> entries = null;
310 entries = complete(ret);
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700311 log.trace(" keystore.getChildren({})", spath);
312 log.trace(" entries keys:{}", entries.keySet());
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800313 if (!entries.isEmpty()) {
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700314 entries.forEach((k, v) -> {
315 String[] names = k.split(ResourceIdParser.NM_CHK);
316 String name = names[0];
317 String nmSpc = ResourceIdParser.getNamespace(names[1]);
318 String keyVal = ResourceIdParser.getKeyVal(names[1]);
319 DataNode.Type type = v.value();
320 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
321 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800322 LeafNode lfnode = readLeaf(tempPath);
323 // 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 .exitNode();
328 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
329 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
330 LeafNode lfnode = readLeaf(mlpath);
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800331 // FIXME there should be builder for copying
332 superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700333 .type(type)
Yuta HIGUCHIda6f56a2018-02-15 11:50:59 -0800334 .leafType(lfnode.leafType())
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700335 .addLeafListValue(lfnode.value())
336 .exitNode();
337 //TODO this alone should be sufficient and take the nm, nmspc too
338 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
339 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
340 .type(type);
341 readInner(tempBldr, tempPath);
342 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
343 DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
344 .type(type);
345 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
346 String[] keys = k.split(ResourceIdParser.KEY_CHK);
347 for (int i = 1; i < keys.length; i++) {
348 //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
349 //LeafNode lfnd = readLeaf(curKey);
350 String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
351 tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
352 }
353 readInner(tempBldr, tempPath);
354 } else {
355 throw new FailedException("Invalid node type");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800356 }
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700357 });
358 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800359 superBldr.exitNode();
360 }
361
362 private LeafNode readLeaf(String path) {
363 return objectStore.get(path).value();
364 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700365
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700366 private void parseForUpdate(String path, DataNode node) {
367 if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
368 addLeaf(path, (LeafNode) node);
369 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
370 path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
371 addLeaf(path, (LeafNode) node);
372 } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
373 traverseInner(path, (InnerNode) node);
374 } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
375 path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
376 traverseInner(path, (InnerNode) node);
377 } else {
378 throw new FailedException("Invalid node type");
379 }
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 Punnassery0da1a9c2017-05-17 16:16:22 -0700383 public CompletableFuture<Boolean> updateNode(ResourceId complete, DataNode node) {
384 CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
Sithara Punnassery0da1a9c2017-05-17 16:16:22 -0700385 String spath = ResourceIdParser.parseResId(complete);
386 if (spath == null) {
387 throw new FailedException("Invalid RsourceId, cannot update Node");
388 }
389 if (spath.compareTo(ResourceIdParser.ROOT) != 0) {
390 if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
391 throw new FailedException("Node or parent doesnot exist, cannot update");
392 }
393 }
394 spath = ResourceIdParser.appendNodeKey(spath, node.key());
395 parseForUpdate(spath, node);
396 return eventFuture;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800397 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700398
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800399 @Override
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700400 public CompletableFuture<Boolean> nodeExist(ResourceId complete) {
401 Boolean stat = true;
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700402 String spath = ResourceIdParser.parseResId(complete);
403 if (spath == null) {
404 stat = false;
405 } else if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
406 stat = false;
407 }
408 return CompletableFuture.completedFuture(stat);
409 }
410
411 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800412 public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800413 throw new FailedException("Not yet implemented");
414 }
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700415
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800416 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800417 public CompletableFuture<Boolean> deleteNode(ResourceId path) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800418 throw new FailedException("Not yet implemented");
419 }
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800420
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700421 private void deleteInner(String spath) {
422 CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
423 DocumentPath.from(spath));
424 Map<String, Versioned<DataNode.Type>> entries = null;
425 entries = complete(ret);
Sithara Punnassery18ffcc72017-05-18 14:24:30 -0700426 if ((entries != null) && (!entries.isEmpty())) {
427 entries.forEach((k, v) -> {
428 String[] names = k.split(ResourceIdParser.NM_CHK);
429 String name = names[0];
430 String nmSpc = ResourceIdParser.getNamespace(names[1]);
431 String keyVal = ResourceIdParser.getKeyVal(names[1]);
432 DataNode.Type type = v.value();
433 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
434 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
435 removeLeaf(tempPath);
436 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
437 String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
438 removeLeaf(mlpath);
439 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
440 deleteInner(tempPath);
441 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
442 tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
443 deleteInner(tempPath);
444 } else {
445 throw new FailedException("Invalid node type");
446 }
447 });
448 }
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700449 log.trace(" keystore.removeNode({})", spath);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700450 keystore.removeNode(DocumentPath.from(spath));
451 }
452
453 private void removeLeaf(String path) {
Yuta HIGUCHI9285d972017-10-16 16:15:00 -0700454 log.trace(" keystore.removeNode({})", path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700455 keystore.removeNode(DocumentPath.from(path));
456 objectStore.remove(path);
457 }
458
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800459 @Override
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800460 public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
461 String spath = ResourceIdParser.parseResId(path);
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700462 if (spath == null) {
Sithara Punnasserybc9edb12017-07-20 14:32:33 -0700463 throw new FailedException("Invalid RsourceId, cannot delete Node");
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700464 }
465 if (spath.compareTo(ResourceIdParser.ROOT) == 0) {
466 throw new FailedException("Cannot delete Root");
467 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800468 DocumentPath dpath = DocumentPath.from(spath);
469 DataNode.Type type = null;
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700470 CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
471 type = completeVersioned(ret);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800472 if (type == null) {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700473 throw new FailedException("Cannot delete, Requested node or some of the parents" +
Henry Yu5c54e772017-04-19 14:13:56 -0400474 "are not present in the requested path");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800475 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700476 DataNode retVal = null;
477 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
478 removeLeaf(spath);
479 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
480 removeLeaf(spath);
481 } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
482 deleteInner(spath);
483 } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
484 deleteInner(spath);
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800485 } else {
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700486 throw new FailedException("Invalid node type");
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800487 }
Sithara Punnasserye4ab4f22017-03-27 19:11:00 -0700488 return CompletableFuture.completedFuture(true);
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800489 }
490
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800491 public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
492 @Override
493 public void event(DocumentTreeEvent<DataNode.Type> event) {
494 DynamicConfigEvent.Type type;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800495 ResourceId path;
496 switch (event.type()) {
497 case CREATED:
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800498 type = NODE_ADDED;
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700499 //log.info("NODE added in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800500 break;
501 case UPDATED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700502 //log.info("NODE updated in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800503 type = NODE_UPDATED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800504 break;
505 case DELETED:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700506 //log.info("NODE deleted in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800507 type = NODE_DELETED;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800508 break;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800509 default:
Sithara Punnassery4cd2ced2017-03-17 17:36:43 -0700510 //log.info("UNKNOWN operation in store");
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800511 type = UNKNOWN_OPRN;
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800512 }
Yuta HIGUCHIdbc08c02018-02-12 16:40:05 -0800513 // FIXME don't use ResourceIdParser
Sithara Punnassery44e2a702017-03-06 15:38:10 -0800514 path = ResourceIdParser.getResId(event.path().pathElements());
515 notifyDelegate(new DynamicConfigEvent(type, path));
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800516 }
517 }
518
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800519 public class InternalMapListener implements MapEventListener<String, LeafNode> {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800520 @Override
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800521 public void event(MapEvent<String, LeafNode> event) {
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800522 switch (event.type()) {
523 case INSERT:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800524 //log.info("NODE created in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800525 break;
526 case UPDATE:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800527 //log.info("NODE updated in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800528 break;
529 case REMOVE:
530 default:
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800531 //log.info("NODE removed in store");
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800532 break;
533 }
Sithara Punnassery9306e6b2017-02-06 15:38:19 -0800534 }
535 }
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800536
537 private <T> T complete(CompletableFuture<T> future) {
538 try {
539 return future.get();
540 } catch (InterruptedException e) {
541 Thread.currentThread().interrupt();
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700542 throw new FailedException(e.getCause().getMessage());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800543 } catch (ExecutionException e) {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700544 if (e.getCause() instanceof IllegalDocumentModificationException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700545 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 -0700546 e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800547 } else if (e.getCause() instanceof NoSuchDocumentPathException) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700548 throw new FailedException("ResourceId does not exist", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800549 } else {
Yuta HIGUCHIea1fe522017-09-01 14:24:02 -0700550 throw new FailedException("Datastore operation failed", e.getCause());
Sithara Punnassery4b091dc2017-03-02 17:22:40 -0800551 }
552 }
553 }
554
555 private <T> T completeVersioned(CompletableFuture<Versioned<T>> future) {
Yuta HIGUCHI3b5d64e2017-09-12 22:44:22 -0700556 return Optional.ofNullable(complete(future))
557 .map(Versioned::value)
558 .orElse(null);
559 }
560}