2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.sal.restconf.impl;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.concurrent.CountDownLatch;
23 import javax.annotation.Nullable;
24 import javax.ws.rs.core.Response.Status;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
29 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
35 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
36 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
37 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
40 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
41 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
42 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
43 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
44 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.common.QName;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
51 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
53 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
61 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
62 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
63 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
64 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
65 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
66 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
67 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
68 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
70 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
74 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 public class BrokerFacade {
79 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
81 private final static BrokerFacade INSTANCE = new BrokerFacade();
82 private volatile DOMRpcService rpcService;
83 private volatile ConsumerSession context;
84 private DOMDataBroker domDataBroker;
85 private DOMNotificationService domNotification;
87 private BrokerFacade() {}
89 public void setRpcService(final DOMRpcService router) {
90 this.rpcService = router;
93 public void setDomNotificationService(final DOMNotificationService domNotification) {
94 this.domNotification = domNotification;
97 public void setContext(final ConsumerSession context) {
98 this.context = context;
101 public static BrokerFacade getInstance() {
102 return BrokerFacade.INSTANCE;
105 private void checkPreconditions() {
106 if (this.context == null || this.domDataBroker == null) {
107 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
112 * Read config data by path
118 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
119 return readConfigurationData(path, null);
123 * Read config data by path
128 * - value of with-defaults parameter
131 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
132 checkPreconditions();
133 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path, withDefa);
137 * Read config data from mount point by path.
140 * - mount point for reading data
145 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
146 final YangInstanceIdentifier path) {
147 return readConfigurationData(mountPoint, path, null);
151 * Read config data from mount point by path.
154 * - mount point for reading data
158 * - value of with-defaults parameter
161 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
162 final String withDefa) {
163 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
164 if (domDataBrokerService.isPresent()) {
165 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path,
168 final String errMsg = "DOM data broker service isn't available for mount point " + path;
170 throw new RestconfDocumentedException(errMsg);
174 * Read operational data by path.
180 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
181 checkPreconditions();
182 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
186 * Read operational data from mount point by path.
189 * - mount point for reading data
194 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
195 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
196 if (domDataBrokerService.isPresent()) {
197 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
199 final String errMsg = "DOM data broker service isn't available for mount point " + path;
201 throw new RestconfDocumentedException(errMsg);
205 * <b>PUT configuration data</b>
207 * Prepare result(status) for PUT operation and PUT data via transaction.
208 * Return wrapped status and future from PUT.
210 * @param globalSchema
211 * - used by merge parents (if contains list)
218 * @return wrapper of status and future of PUT
220 public PutResult commitConfigurationDataPut(
221 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
222 final String insert, final String point) {
223 Preconditions.checkNotNull(globalSchema);
224 Preconditions.checkNotNull(path);
225 Preconditions.checkNotNull(payload);
227 checkPreconditions();
229 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
230 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
232 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
233 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
234 return new PutResult(status, future);
238 * <b>PUT configuration data (Mount point)</b>
240 * Prepare result(status) for PUT operation and PUT data via transaction.
241 * Return wrapped status and future from PUT.
244 * - mount point for getting transaction for operation and schema
245 * context for merging parents(if contains list)
252 * @return wrapper of status and future of PUT
254 public PutResult commitMountPointDataPut(
255 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
256 final String insert, final String point) {
257 Preconditions.checkNotNull(mountPoint);
258 Preconditions.checkNotNull(path);
259 Preconditions.checkNotNull(payload);
261 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
262 if (domDataBrokerService.isPresent()) {
263 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
264 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
265 ? Status.OK : Status.CREATED;
266 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
267 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
269 return new PutResult(status, future);
271 final String errMsg = "DOM data broker service isn't available for mount point " + path;
273 throw new RestconfDocumentedException(errMsg);
276 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
277 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
279 // get new transaction and schema context on server or on mounted device
280 final SchemaContext schemaContext;
281 final DOMDataReadWriteTransaction patchTransaction;
282 if (mountPoint == null) {
283 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
284 patchTransaction = this.domDataBroker.newReadWriteTransaction();
286 schemaContext = mountPoint.getSchemaContext();
288 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
290 if (optional.isPresent()) {
291 patchTransaction = optional.get().newReadWriteTransaction();
293 // if mount point does not have broker it is not possible to continue and global error is reported
294 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
295 patchContext.getPatchId(), mountPoint.getIdentifier());
296 return new PATCHStatusContext(
297 patchContext.getPatchId(),
300 ImmutableList.of(new RestconfError(
301 ErrorType.APPLICATION,
302 ErrorTag.OPERATION_FAILED,
303 "DOM data broker service isn't available for mount point "
304 + mountPoint.getIdentifier()))
309 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
310 List<RestconfError> editErrors;
311 boolean withoutError = true;
313 for (final PATCHEntity patchEntity : patchContext.getData()) {
314 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
320 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
321 patchEntity.getNode(), schemaContext);
322 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
323 } catch (final RestconfDocumentedException e) {
324 LOG.error("Error call http PATCH operation {} on target {}",
326 patchEntity.getTargetNode().toString());
328 editErrors = new ArrayList<>();
329 editErrors.addAll(e.getErrors());
330 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
331 withoutError = false;
338 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
339 .getTargetNode(), patchEntity.getNode(), schemaContext);
340 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
341 } catch (final RestconfDocumentedException e) {
342 LOG.error("Error call http PATCH operation {} on target {}",
344 patchEntity.getTargetNode().toString());
346 editErrors = new ArrayList<>();
347 editErrors.addAll(e.getErrors());
348 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
349 withoutError = false;
356 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
358 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
359 } catch (final RestconfDocumentedException e) {
360 LOG.error("Error call http PATCH operation {} on target {}",
362 patchEntity.getTargetNode().toString());
364 editErrors = new ArrayList<>();
365 editErrors.addAll(e.getErrors());
366 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
367 withoutError = false;
374 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
376 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
377 } catch (final RestconfDocumentedException e) {
378 LOG.error("Error call http PATCH operation {} on target {}",
380 patchEntity.getTargetNode().toString());
382 editErrors = new ArrayList<>();
383 editErrors.addAll(e.getErrors());
384 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
385 withoutError = false;
392 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
393 patchEntity.getNode(), schemaContext);
394 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
395 } catch (final RestconfDocumentedException e) {
396 LOG.error("Error call http PATCH operation {} on target {}",
398 patchEntity.getTargetNode().toString());
400 editErrors = new ArrayList<>();
401 editErrors.addAll(e.getErrors());
402 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
403 withoutError = false;
408 LOG.error("Unsupported http PATCH operation {} on target {}",
410 patchEntity.getTargetNode().toString());
415 // if errors then cancel transaction and return error status
417 patchTransaction.cancel();
418 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
421 // if no errors commit transaction
422 final CountDownLatch waiter = new CountDownLatch(1);
423 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
424 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
426 Futures.addCallback(future, new FutureCallback<Void>() {
428 public void onSuccess(@Nullable final Void result) {
429 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
435 public void onFailure(final Throwable t) {
436 // if commit failed it is global error
437 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
438 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
439 false, ImmutableList.of(
440 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
446 return status.getStatus();
449 // POST configuration
450 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
451 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
452 final String insert, final String point) {
453 checkPreconditions();
454 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
455 globalSchema, insert, point);
458 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
459 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
460 final String insert, final String point) {
461 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
462 if (domDataBrokerService.isPresent()) {
463 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
464 payload, mountPoint.getSchemaContext(), insert, point);
466 final String errMsg = "DOM data broker service isn't available for mount point " + path;
468 throw new RestconfDocumentedException(errMsg);
471 // DELETE configuration
472 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
473 final YangInstanceIdentifier path) {
474 checkPreconditions();
475 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
478 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
479 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
480 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
481 if (domDataBrokerService.isPresent()) {
482 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
484 final String errMsg = "DOM data broker service isn't available for mount point " + path;
486 throw new RestconfDocumentedException(errMsg);
490 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
491 checkPreconditions();
492 if (this.rpcService == null) {
493 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
495 LOG.trace("Invoke RPC {} with input: {}", type, input);
496 return this.rpcService.invokeRpc(type, input);
499 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
500 final ListenerAdapter listener) {
501 checkPreconditions();
503 if (listener.isListening()) {
507 final YangInstanceIdentifier path = listener.getPath();
508 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
509 datastore, path, listener, scope);
511 listener.setRegistration(registration);
514 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
515 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
516 return readDataViaTransaction(transaction, datastore, path, null);
519 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
520 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
521 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
524 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
525 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
526 prepareDataByParamWithDef(optional.get(), path, withDefa);
527 } catch (ReadFailedException e) {
528 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
529 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
533 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
534 final YangInstanceIdentifier path, final String withDefa) {
544 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
547 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
548 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
549 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
550 if (result instanceof ContainerNode) {
551 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
552 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
553 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
554 return builder.build();
556 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
557 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
558 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
559 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
560 return builder.build();
564 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
565 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
566 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
567 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
568 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
569 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
570 if (child instanceof ContainerNode) {
571 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
572 Builders.containerBuilder((ContainerSchemaNode) childSchema);
573 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
574 builder.withChild(childBuilder.build());
575 } else if (child instanceof MapNode) {
576 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
577 Builders.mapBuilder((ListSchemaNode) childSchema);
578 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
579 ((ListSchemaNode) childSchema).getKeyDefinition());
580 builder.withChild(childBuilder.build());
581 } else if (child instanceof LeafNode) {
582 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
583 final String nodeVal = ((LeafNode<String>) child).getValue();
584 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
585 Builders.leafBuilder((LeafSchemaNode) childSchema);
586 if (keys.contains(child.getNodeType())) {
587 leafBuilder.withValue(((LeafNode) child).getValue());
588 builder.withChild(leafBuilder.build());
591 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
592 leafBuilder.withValue(((LeafNode) child).getValue());
593 builder.withChild(leafBuilder.build());
596 if (defaultVal != null && defaultVal.equals(nodeVal)) {
597 leafBuilder.withValue(((LeafNode) child).getValue());
598 builder.withChild(leafBuilder.build());
606 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
607 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
608 final List<QName> keys) {
609 for (final MapEntryNode mapEntryNode : result.getValue()) {
610 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
611 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
612 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
613 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
614 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
615 builder.withChild(mapEntryBuilder.build());
619 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
620 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
621 final YangInstanceIdentifier actualPath, final boolean trim) {
622 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
623 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
624 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
625 if(child instanceof ContainerNode){
626 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
627 Builders.containerBuilder((ContainerSchemaNode) childSchema);
628 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
629 builder.withChild(builderChild.build());
630 } else if (child instanceof MapNode) {
631 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
632 Builders.mapBuilder((ListSchemaNode) childSchema);
633 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
634 ((ListSchemaNode) childSchema).getKeyDefinition());
635 builder.withChild(childBuilder.build());
636 } else if (child instanceof LeafNode) {
637 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
638 final String nodeVal = ((LeafNode<String>) child).getValue();
639 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
640 Builders.leafBuilder((LeafSchemaNode) childSchema);
642 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
643 leafBuilder.withValue(((LeafNode) child).getValue());
644 builder.withChild(leafBuilder.build());
647 if (defaultVal != null && defaultVal.equals(nodeVal)) {
648 leafBuilder.withValue(((LeafNode) child).getValue());
649 builder.withChild(leafBuilder.build());
657 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
659 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
660 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
661 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
662 final String insert, final String point) {
663 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
664 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
665 return rWTransaction.submit();
669 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
671 private void postDataWithinTransaction(
672 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
673 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
674 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
675 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
678 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
679 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
680 final SchemaContext schemaContext, final String insert, final String point) {
681 if (insert == null) {
682 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
684 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
685 checkItemDoesNotExists(rWTransaction, datastore, path);
688 if(schemaNode instanceof ListSchemaNode){
689 final OrderedMapNode readList =
690 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
691 if (readList == null || readList.getValue().isEmpty()) {
692 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
694 rWTransaction.delete(datastore, path.getParent().getParent());
695 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
696 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
700 final OrderedLeafSetNode readLeafList =
701 (OrderedLeafSetNode) readConfigurationData(path.getParent());
702 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
703 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
705 rWTransaction.delete(datastore, path.getParent());
706 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
707 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
713 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
716 if(schemaNode instanceof ListSchemaNode){
717 final OrderedMapNode readList =
718 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
719 if (readList == null || readList.getValue().isEmpty()) {
720 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
722 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
727 final OrderedLeafSetNode<?> readLeafList =
728 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
729 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
730 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
732 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
738 if (schemaNode instanceof ListSchemaNode) {
739 final OrderedMapNode readList =
740 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
741 if (readList == null || readList.getValue().isEmpty()) {
742 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
744 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
749 final OrderedLeafSetNode<?> readLeafList =
750 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
751 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
752 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
754 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
755 readLeafList, false);
760 throw new RestconfDocumentedException(
761 "Used bad value of insert parameter. Possible values are first, last, before or after, "
762 + "but was: " + insert);
767 private void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
768 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
769 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
770 final boolean before) {
771 rWTransaction.delete(datastore, path.getParent().getParent());
772 final InstanceIdentifierContext<?> instanceIdentifier =
773 ControllerContext.getInstance().toInstanceIdentifier(point);
775 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
776 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
785 final NormalizedNode<?, ?> emptySubtree =
786 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
787 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
788 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
790 checkItemDoesNotExists(rWTransaction, datastore, path);
791 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
793 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
794 checkItemDoesNotExists(rWTransaction, datastore, childPath);
795 rWTransaction.put(datastore, childPath, nodeChild);
800 private void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
801 final LogicalDatastoreType datastore,
802 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
803 final String point, final MapNode readList, final boolean before) {
804 rWTransaction.delete(datastore, path.getParent().getParent());
805 final InstanceIdentifierContext<?> instanceIdentifier =
806 ControllerContext.getInstance().toInstanceIdentifier(point);
808 for (final MapEntryNode mapEntryNode : readList.getValue()) {
809 if (mapEntryNode.getIdentifier()
810 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
819 final NormalizedNode<?, ?> emptySubtree =
820 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
821 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
822 for (final MapEntryNode mapEntryNode : readList.getValue()) {
824 checkItemDoesNotExists(rWTransaction, datastore, path);
825 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
827 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
828 checkItemDoesNotExists(rWTransaction, datastore, childPath);
829 rWTransaction.put(datastore, childPath, mapEntryNode);
834 private DataSchemaNode checkListAndOrderedType(final SchemaContext ctx,
835 final YangInstanceIdentifier path) {
836 final YangInstanceIdentifier parent = path.getParent();
837 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
838 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
840 if (dataSchemaNode instanceof ListSchemaNode) {
841 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
842 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
844 return dataSchemaNode;
846 if (dataSchemaNode instanceof LeafListSchemaNode) {
847 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
848 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
850 return dataSchemaNode;
852 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
855 private void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
856 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
857 if (payload instanceof MapNode) {
858 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
859 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
860 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
861 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
862 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
863 checkItemDoesNotExists(rWTransaction, datastore, childPath);
864 rWTransaction.put(datastore, childPath, child);
866 } else if (payload instanceof LeafSetNode) {
867 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
868 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
869 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
870 for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) payload).getValue()) {
871 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
872 checkItemDoesNotExists(rWTransaction, datastore, childPath);
873 rWTransaction.put(datastore, childPath, child);
876 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
880 private void simplePostPut(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
881 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
882 checkItemDoesNotExists(rWTransaction, datastore, path);
883 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
884 rWTransaction.put(datastore, path, payload);
887 private boolean doesItemExist(final DOMDataReadWriteTransaction rWTransaction,
888 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
890 return rWTransaction.exists(store, path).checkedGet();
891 } catch (ReadFailedException e) {
892 rWTransaction.cancel();
893 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
894 e, e.getErrorList());
899 * Check if item already exists. Throws error if it does NOT already exist.
900 * @param rWTransaction Current transaction
901 * @param store Used datastore
902 * @param path Path to item to verify its existence
904 private void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
905 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
906 if (!doesItemExist(rWTransaction, store, path)) {
907 final String errMsg = "Operation via Restconf was not executed because data does not exist";
908 LOG.trace("{}:{}", errMsg, path);
909 rWTransaction.cancel();
910 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
911 ErrorTag.DATA_MISSING);
916 * Check if item does NOT already exist. Throws error if it already exists.
917 * @param rWTransaction Current transaction
918 * @param store Used datastore
919 * @param path Path to item to verify its existence
921 private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
922 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
923 if (doesItemExist(rWTransaction, store, path)) {
924 final String errMsg = "Operation via Restconf was not executed because data already exists";
925 LOG.trace("{}:{}", errMsg, path);
926 rWTransaction.cancel();
927 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
928 ErrorTag.DATA_EXISTS);
933 * PUT data and submit {@link DOMDataReadWriteTransaction}
938 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
939 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
940 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
941 final String insert, final String point) {
942 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
943 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
944 return readWriteTransaction.submit();
948 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
953 private void putDataWithinTransaction(
954 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
955 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
956 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
957 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
960 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
961 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
962 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
963 final String insert, final String point) {
964 if (insert == null) {
965 makePut(rWTransaction, datastore, path, payload, schemaContext);
967 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
968 checkItemDoesNotExists(rWTransaction, datastore, path);
971 if (schemaNode instanceof ListSchemaNode) {
972 final OrderedMapNode readList =
973 (OrderedMapNode) this.readConfigurationData(path.getParent());
974 if (readList == null || readList.getValue().isEmpty()) {
975 simplePut(datastore, path, rWTransaction, schemaContext, payload);
977 rWTransaction.delete(datastore, path.getParent());
978 simplePut(datastore, path, rWTransaction, schemaContext, payload);
979 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
982 final OrderedLeafSetNode<?> readLeafList =
983 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
984 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
985 simplePut(datastore, path, rWTransaction, schemaContext, payload);
987 rWTransaction.delete(datastore, path.getParent());
988 simplePut(datastore, path, rWTransaction, schemaContext, payload);
989 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
995 simplePut(datastore, path, rWTransaction, schemaContext, payload);
998 if (schemaNode instanceof ListSchemaNode) {
999 final OrderedMapNode readList =
1000 (OrderedMapNode) this.readConfigurationData(path.getParent());
1001 if (readList == null || readList.getValue().isEmpty()) {
1002 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1004 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1008 final OrderedLeafSetNode<?> readLeafList =
1009 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1010 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1011 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1013 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1014 readLeafList, true);
1019 if (schemaNode instanceof ListSchemaNode) {
1020 final OrderedMapNode readList =
1021 (OrderedMapNode) this.readConfigurationData(path.getParent());
1022 if (readList == null || readList.getValue().isEmpty()) {
1023 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1025 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1029 final OrderedLeafSetNode<?> readLeafList =
1030 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1031 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1032 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1034 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1035 readLeafList, false);
1040 throw new RestconfDocumentedException(
1041 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1042 + "but was: " + insert);
1047 private void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1048 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1049 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1050 final boolean before) {
1051 rWTransaction.delete(datastore, path.getParent());
1052 final InstanceIdentifierContext<?> instanceIdentifier =
1053 ControllerContext.getInstance().toInstanceIdentifier(point);
1055 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1056 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1065 final NormalizedNode<?, ?> emptySubtree =
1066 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1067 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1068 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1070 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1072 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1073 rWTransaction.put(datastore, childPath, nodeChild);
1078 private void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1079 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1080 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1081 final boolean before) {
1082 rWTransaction.delete(datastore, path.getParent());
1083 final InstanceIdentifierContext<?> instanceIdentifier =
1084 ControllerContext.getInstance().toInstanceIdentifier(point);
1086 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1087 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1096 final NormalizedNode<?, ?> emptySubtree =
1097 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1098 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1099 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1101 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1103 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1104 rWTransaction.put(datastore, childPath, mapEntryNode);
1109 private void makePut(final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1110 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1111 if (payload instanceof MapNode) {
1112 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1113 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1114 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1115 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1116 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1117 writeTransaction.put(datastore, childPath, child);
1120 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1124 private void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1125 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1126 final NormalizedNode<?, ?> payload) {
1127 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1128 writeTransaction.put(datastore, path, payload);
1131 private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1132 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1133 final YangInstanceIdentifier path) {
1134 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1135 checkItemExists(readWriteTransaction, datastore, path);
1136 readWriteTransaction.delete(datastore, path);
1137 return readWriteTransaction.submit();
1140 private void deleteDataWithinTransaction(
1141 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1142 final YangInstanceIdentifier path) {
1143 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1144 writeTransaction.delete(datastore, path);
1147 private void mergeDataWithinTransaction(
1148 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1149 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1150 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1151 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1153 // merging is necessary only for lists otherwise we can call put method
1154 if (payload instanceof MapNode) {
1155 writeTransaction.merge(datastore, path, payload);
1157 writeTransaction.put(datastore, path, payload);
1161 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1162 this.domDataBroker = domDataBroker;
1165 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1166 checkPreconditions();
1168 if (listener.isListening()) {
1172 final SchemaPath path = listener.getSchemaPath();
1173 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1174 .registerNotificationListener(listener, path);
1176 listener.setRegistration(registration);
1179 private final class PATCHStatusContextHelper {
1180 PATCHStatusContext status;
1182 public PATCHStatusContext getStatus() {
1186 public void setStatus(final PATCHStatusContext status) {
1187 this.status = status;
1191 private void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier normalizedPath,
1192 final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) {
1193 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1194 YangInstanceIdentifier rootNormalizedPath = null;
1196 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1198 while (it.hasNext()) {
1199 final PathArgument pathArgument = it.next();
1200 if (rootNormalizedPath == null) {
1201 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1205 normalizedPathWithoutChildArgs.add(pathArgument);
1209 if (normalizedPathWithoutChildArgs.isEmpty()) {
1213 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1215 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1216 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1217 rwTx.merge(store, rootNormalizedPath, parentStructure);