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.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map.Entry;
24 import java.util.concurrent.CountDownLatch;
25 import javax.annotation.Nullable;
26 import javax.ws.rs.core.Response.Status;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
38 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
39 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
43 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
44 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
45 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
46 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
47 import org.opendaylight.yangtools.concepts.ListenerRegistration;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.common.RpcError;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
54 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
56 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
64 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
65 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
66 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
67 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
68 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
69 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
70 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
71 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
77 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
81 public class BrokerFacade {
82 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
83 private static final BrokerFacade INSTANCE = new BrokerFacade();
85 private volatile DOMRpcService rpcService;
87 private DOMDataBroker domDataBroker;
88 private DOMNotificationService domNotification;
90 private BrokerFacade() {}
92 public void setRpcService(final DOMRpcService router) {
93 this.rpcService = router;
96 public void setDomNotificationService(final DOMNotificationService domNotification) {
97 this.domNotification = domNotification;
100 public static BrokerFacade getInstance() {
101 return BrokerFacade.INSTANCE;
104 private void checkPreconditions() {
105 if (this.domDataBroker == null) {
106 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
111 * Read config data by path.
117 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
118 return readConfigurationData(path, null);
122 * Read config data by path.
127 * value of with-defaults parameter
130 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
131 checkPreconditions();
132 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
133 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
138 * Read config data from mount point by path.
141 * mount point for reading data
146 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
147 final YangInstanceIdentifier path) {
148 return readConfigurationData(mountPoint, path, null);
152 * Read config data from mount point by path.
155 * mount point for reading data
159 * value of with-defaults parameter
162 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
163 final String withDefa) {
164 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
165 if (domDataBrokerService.isPresent()) {
166 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
167 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
170 final String errMsg = "DOM data broker service isn't available for mount point " + path;
172 throw new RestconfDocumentedException(errMsg);
176 * Read operational data by path.
182 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
183 checkPreconditions();
185 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
186 return readDataViaTransaction(tx, OPERATIONAL, path);
191 * Read operational data from mount point by path.
194 * mount point for reading data
199 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
200 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
201 if (domDataBrokerService.isPresent()) {
202 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
203 return readDataViaTransaction(tx, OPERATIONAL, path);
206 final String errMsg = "DOM data broker service isn't available for mount point " + path;
208 throw new RestconfDocumentedException(errMsg);
212 * <b>PUT configuration data</b>
215 * Prepare result(status) for PUT operation and PUT data via transaction.
216 * Return wrapped status and future from PUT.
218 * @param globalSchema
219 * used by merge parents (if contains list)
228 * @return wrapper of status and future of PUT
230 public PutResult commitConfigurationDataPut(
231 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
232 final String insert, final String point) {
233 Preconditions.checkNotNull(globalSchema);
234 Preconditions.checkNotNull(path);
235 Preconditions.checkNotNull(payload);
237 checkPreconditions();
239 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
240 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
242 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
243 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
244 return new PutResult(status, future);
248 * <b>PUT configuration data (Mount point)</b>
251 * Prepare result(status) for PUT operation and PUT data via transaction.
252 * Return wrapped status and future from PUT.
255 * mount point for getting transaction for operation and schema
256 * context for merging parents(if contains list)
265 * @return wrapper of status and future of PUT
267 public PutResult commitMountPointDataPut(
268 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
269 final String insert, final String point) {
270 Preconditions.checkNotNull(mountPoint);
271 Preconditions.checkNotNull(path);
272 Preconditions.checkNotNull(payload);
274 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
275 if (domDataBrokerService.isPresent()) {
276 final DOMDataReadWriteTransaction newReadWriteTransaction =
277 domDataBrokerService.get().newReadWriteTransaction();
278 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
279 ? Status.OK : Status.CREATED;
280 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
281 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
283 return new PutResult(status, future);
285 final String errMsg = "DOM data broker service isn't available for mount point " + path;
287 throw new RestconfDocumentedException(errMsg);
290 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
292 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
294 // get new transaction and schema context on server or on mounted device
295 final SchemaContext schemaContext;
296 final DOMDataReadWriteTransaction patchTransaction;
297 if (mountPoint == null) {
298 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
299 patchTransaction = this.domDataBroker.newReadWriteTransaction();
301 schemaContext = mountPoint.getSchemaContext();
303 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
305 if (optional.isPresent()) {
306 patchTransaction = optional.get().newReadWriteTransaction();
308 // if mount point does not have broker it is not possible to continue and global error is reported
309 LOG.error("Http Patch {} has failed - device {} does not support broker service",
310 patchContext.getPatchId(), mountPoint.getIdentifier());
311 return new PatchStatusContext(
312 patchContext.getPatchId(),
315 ImmutableList.of(new RestconfError(
316 ErrorType.APPLICATION,
317 ErrorTag.OPERATION_FAILED,
318 "DOM data broker service isn't available for mount point "
319 + mountPoint.getIdentifier()))
324 final List<PatchStatusEntity> editCollection = new ArrayList<>();
325 List<RestconfError> editErrors;
326 boolean withoutError = true;
328 for (final PatchEntity patchEntity : patchContext.getData()) {
329 final PatchEditOperation operation = patchEntity.getOperation();
334 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
335 patchEntity.getNode(), schemaContext);
336 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
337 } catch (final RestconfDocumentedException e) {
338 LOG.error("Error call http Patch operation {} on target {}",
340 patchEntity.getTargetNode().toString());
342 editErrors = new ArrayList<>();
343 editErrors.addAll(e.getErrors());
344 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
345 withoutError = false;
352 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
353 .getTargetNode(), patchEntity.getNode(), schemaContext);
354 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
355 } catch (final RestconfDocumentedException e) {
356 LOG.error("Error call http Patch operation {} on target {}",
358 patchEntity.getTargetNode().toString());
360 editErrors = new ArrayList<>();
361 editErrors.addAll(e.getErrors());
362 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
363 withoutError = false;
370 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
372 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
373 } catch (final RestconfDocumentedException e) {
374 LOG.error("Error call http Patch operation {} on target {}",
376 patchEntity.getTargetNode().toString());
378 editErrors = new ArrayList<>();
379 editErrors.addAll(e.getErrors());
380 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
381 withoutError = false;
388 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
390 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
391 } catch (final RestconfDocumentedException e) {
392 LOG.error("Error call http Patch operation {} on target {}",
394 patchEntity.getTargetNode().toString());
396 editErrors = new ArrayList<>();
397 editErrors.addAll(e.getErrors());
398 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
399 withoutError = false;
406 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
407 patchEntity.getNode(), schemaContext);
408 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
409 } catch (final RestconfDocumentedException e) {
410 LOG.error("Error call http Patch operation {} on target {}",
412 patchEntity.getTargetNode().toString());
414 editErrors = new ArrayList<>();
415 editErrors.addAll(e.getErrors());
416 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
417 withoutError = false;
422 LOG.error("Unsupported http Patch operation {} on target {}",
424 patchEntity.getTargetNode().toString());
429 // if errors then cancel transaction and return error status
431 patchTransaction.cancel();
432 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
435 // if no errors commit transaction
436 final CountDownLatch waiter = new CountDownLatch(1);
437 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
438 final PatchStatusContextHelper status = new PatchStatusContextHelper();
440 Futures.addCallback(future, new FutureCallback<Void>() {
442 public void onSuccess(@Nullable final Void result) {
443 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
449 public void onFailure(final Throwable throwable) {
450 // if commit failed it is global error
451 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
452 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
453 false, ImmutableList.of(
454 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
460 return status.getStatus();
463 // POST configuration
464 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
465 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
466 final String insert, final String point) {
467 checkPreconditions();
468 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
469 globalSchema, insert, point);
472 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
473 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
474 final String insert, final String point) {
475 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
476 if (domDataBrokerService.isPresent()) {
477 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
478 payload, mountPoint.getSchemaContext(), insert, point);
480 final String errMsg = "DOM data broker service isn't available for mount point " + path;
482 throw new RestconfDocumentedException(errMsg);
485 // DELETE configuration
486 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
487 final YangInstanceIdentifier path) {
488 checkPreconditions();
489 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
492 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
493 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
494 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
495 if (domDataBrokerService.isPresent()) {
496 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
498 final String errMsg = "DOM data broker service isn't available for mount point " + path;
500 throw new RestconfDocumentedException(errMsg);
504 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
505 final NormalizedNode<?, ?> input) {
506 checkPreconditions();
507 if (this.rpcService == null) {
508 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
510 LOG.trace("Invoke RPC {} with input: {}", type, input);
511 return this.rpcService.invokeRpc(type, input);
514 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
515 final ListenerAdapter listener) {
516 checkPreconditions();
518 if (listener.isListening()) {
522 final YangInstanceIdentifier path = listener.getPath();
523 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
524 datastore, path, listener, scope);
526 listener.setRegistration(registration);
529 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
530 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
531 return readDataViaTransaction(transaction, datastore, path, null);
534 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
535 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
536 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
539 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
540 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
541 prepareDataByParamWithDef(optional.get(), path, withDefa);
542 } catch (ReadFailedException e) {
543 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
544 for (final RpcError error : e.getErrorList()) {
545 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
546 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
547 throw new RestconfDocumentedException(
550 ErrorTag.RESOURCE_DENIED_TRANSPORT);
553 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
557 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
558 final YangInstanceIdentifier path, final String withDefa) {
568 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
571 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
572 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
573 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
574 if (result instanceof ContainerNode) {
575 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
576 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
577 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
578 return builder.build();
581 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
582 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
583 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
584 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
585 return builder.build();
588 private void buildMapEntryBuilder(
589 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
590 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
591 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
592 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
593 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
594 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
595 if (child instanceof ContainerNode) {
596 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
597 Builders.containerBuilder((ContainerSchemaNode) childSchema);
598 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
599 builder.withChild(childBuilder.build());
600 } else if (child instanceof MapNode) {
601 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
602 Builders.mapBuilder((ListSchemaNode) childSchema);
603 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
604 ((ListSchemaNode) childSchema).getKeyDefinition());
605 builder.withChild(childBuilder.build());
606 } else if (child instanceof LeafNode) {
607 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
608 final String nodeVal = ((LeafNode<String>) child).getValue();
609 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
610 Builders.leafBuilder((LeafSchemaNode) childSchema);
611 if (keys.contains(child.getNodeType())) {
612 leafBuilder.withValue(((LeafNode<?>) child).getValue());
613 builder.withChild(leafBuilder.build());
616 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
617 leafBuilder.withValue(((LeafNode<?>) child).getValue());
618 builder.withChild(leafBuilder.build());
621 if (defaultVal != null && defaultVal.equals(nodeVal)) {
622 leafBuilder.withValue(((LeafNode<?>) child).getValue());
623 builder.withChild(leafBuilder.build());
631 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
632 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
633 final List<QName> keys) {
634 for (final MapEntryNode mapEntryNode : result.getValue()) {
635 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
636 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
637 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
638 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
639 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
640 builder.withChild(mapEntryBuilder.build());
644 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
645 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
646 final YangInstanceIdentifier actualPath, final boolean trim) {
647 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
648 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
649 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
650 if (child instanceof ContainerNode) {
651 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
652 Builders.containerBuilder((ContainerSchemaNode) childSchema);
653 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
654 builder.withChild(builderChild.build());
655 } else if (child instanceof MapNode) {
656 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
657 Builders.mapBuilder((ListSchemaNode) childSchema);
658 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
659 ((ListSchemaNode) childSchema).getKeyDefinition());
660 builder.withChild(childBuilder.build());
661 } else if (child instanceof LeafNode) {
662 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
663 final String nodeVal = ((LeafNode<String>) child).getValue();
664 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
665 Builders.leafBuilder((LeafSchemaNode) childSchema);
667 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
668 leafBuilder.withValue(((LeafNode<?>) child).getValue());
669 builder.withChild(leafBuilder.build());
672 if (defaultVal != null && defaultVal.equals(nodeVal)) {
673 leafBuilder.withValue(((LeafNode<?>) child).getValue());
674 builder.withChild(leafBuilder.build());
682 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
684 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
685 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
686 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
687 final String insert, final String point) {
688 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
689 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
690 return rwTransaction.submit();
694 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
696 private void postDataWithinTransaction(
697 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
698 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
699 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
700 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
703 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
704 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
705 final SchemaContext schemaContext, final String insert, final String point) {
706 if (insert == null) {
707 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
711 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
712 checkItemDoesNotExists(rwTransaction, datastore, path);
715 if (schemaNode instanceof ListSchemaNode) {
716 final OrderedMapNode readList =
717 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
718 if (readList == null || readList.getValue().isEmpty()) {
719 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
721 rwTransaction.delete(datastore, path.getParent().getParent());
722 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
723 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
727 final OrderedLeafSetNode<?> readLeafList =
728 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
729 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
730 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
732 rwTransaction.delete(datastore, path.getParent());
733 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
734 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
740 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
743 if (schemaNode instanceof ListSchemaNode) {
744 final OrderedMapNode readList =
745 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
746 if (readList == null || readList.getValue().isEmpty()) {
747 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
749 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
754 final OrderedLeafSetNode<?> readLeafList =
755 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
756 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
757 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
759 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
765 if (schemaNode instanceof ListSchemaNode) {
766 final OrderedMapNode readList =
767 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
768 if (readList == null || readList.getValue().isEmpty()) {
769 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
771 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
776 final OrderedLeafSetNode<?> readLeafList =
777 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
778 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
779 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
781 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
782 readLeafList, false);
787 throw new RestconfDocumentedException(
788 "Used bad value of insert parameter. Possible values are first, last, before or after, "
789 + "but was: " + insert);
793 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
794 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
795 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
796 final boolean before) {
797 rwTransaction.delete(datastore, path.getParent().getParent());
798 final InstanceIdentifierContext<?> instanceIdentifier =
799 ControllerContext.getInstance().toInstanceIdentifier(point);
800 int lastItemPosition = 0;
801 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
802 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
810 int lastInsertedPosition = 0;
811 final NormalizedNode<?, ?> emptySubtree =
812 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
813 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
814 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
815 if (lastInsertedPosition == lastItemPosition) {
816 checkItemDoesNotExists(rwTransaction, datastore, path);
817 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
819 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
820 checkItemDoesNotExists(rwTransaction, datastore, childPath);
821 rwTransaction.put(datastore, childPath, nodeChild);
822 lastInsertedPosition++;
826 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
827 final LogicalDatastoreType datastore,
828 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
829 final String point, final MapNode readList, final boolean before) {
830 rwTransaction.delete(datastore, path.getParent().getParent());
831 final InstanceIdentifierContext<?> instanceIdentifier =
832 ControllerContext.getInstance().toInstanceIdentifier(point);
833 int lastItemPosition = 0;
834 for (final MapEntryNode mapEntryNode : readList.getValue()) {
835 if (mapEntryNode.getIdentifier()
836 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
844 int lastInsertedPosition = 0;
845 final NormalizedNode<?, ?> emptySubtree =
846 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
847 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
848 for (final MapEntryNode mapEntryNode : readList.getValue()) {
849 if (lastInsertedPosition == lastItemPosition) {
850 checkItemDoesNotExists(rwTransaction, datastore, path);
851 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
853 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
854 checkItemDoesNotExists(rwTransaction, datastore, childPath);
855 rwTransaction.put(datastore, childPath, mapEntryNode);
856 lastInsertedPosition++;
860 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
861 final YangInstanceIdentifier parent = path.getParent();
862 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
863 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
865 if (dataSchemaNode instanceof ListSchemaNode) {
866 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
867 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
869 return dataSchemaNode;
871 if (dataSchemaNode instanceof LeafListSchemaNode) {
872 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
873 throw new RestconfDocumentedException(
874 "Insert parameter can be used only with ordered-by user leaf-list.");
876 return dataSchemaNode;
878 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
881 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
882 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
883 final SchemaContext schemaContext) {
884 final Collection<? extends NormalizedNode<?, ?>> children;
885 if (payload instanceof MapNode) {
886 children = ((MapNode) payload).getValue();
887 } else if (payload instanceof LeafSetNode) {
888 children = ((LeafSetNode<?>) payload).getValue();
890 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
894 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
895 if (children.isEmpty()) {
896 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
897 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
901 // Kick off batch existence check first...
902 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
904 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
905 // result of the existence checks...
906 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
907 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
908 for (final NormalizedNode<?, ?> child : children) {
909 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
910 // as that would allow us to skip the existence checks
911 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
914 // ... finally collect existence checks and abort the transaction if any of them failed.
915 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
917 failure = check.getFailure();
918 } catch (InterruptedException e) {
919 rwTransaction.cancel();
920 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
923 if (failure != null) {
924 rwTransaction.cancel();
925 final ReadFailedException e = failure.getValue();
927 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
928 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
931 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
936 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
937 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
938 final SchemaContext schemaContext) {
939 checkItemDoesNotExists(rwTransaction, datastore, path);
940 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
941 rwTransaction.put(datastore, path, payload);
944 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
945 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
947 return rwTransaction.exists(store, path).checkedGet();
948 } catch (ReadFailedException e) {
949 rwTransaction.cancel();
950 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
951 e, e.getErrorList());
956 * Check if item already exists. Throws error if it does NOT already exist.
957 * @param rwTransaction Current transaction
958 * @param store Used datastore
959 * @param path Path to item to verify its existence
961 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
962 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
963 if (!doesItemExist(rwTransaction, store, path)) {
964 final String errMsg = "Operation via Restconf was not executed because data does not exist";
965 LOG.trace("{}:{}", errMsg, path);
966 rwTransaction.cancel();
967 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
968 ErrorTag.DATA_MISSING);
973 * Check if item does NOT already exist. Throws error if it already exists.
974 * @param rwTransaction Current transaction
975 * @param store Used datastore
976 * @param path Path to item to verify its existence
978 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
979 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
980 if (doesItemExist(rwTransaction, store, path)) {
981 final String errMsg = "Operation via Restconf was not executed because data already exists";
982 LOG.trace("{}:{}", errMsg, path);
983 rwTransaction.cancel();
984 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
985 ErrorTag.DATA_EXISTS);
990 * PUT data and submit {@link DOMDataReadWriteTransaction}.
997 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
998 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
999 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1000 final String insert, final String point) {
1001 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1002 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1003 return readWriteTransaction.submit();
1007 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1009 private void putDataWithinTransaction(
1010 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1011 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1012 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1013 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1016 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1017 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1018 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1019 final String insert, final String point) {
1020 if (insert == null) {
1021 makePut(rwTransaction, datastore, path, payload, schemaContext);
1025 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1026 checkItemDoesNotExists(rwTransaction, datastore, path);
1029 if (schemaNode instanceof ListSchemaNode) {
1030 final OrderedMapNode readList =
1031 (OrderedMapNode) this.readConfigurationData(path.getParent());
1032 if (readList == null || readList.getValue().isEmpty()) {
1033 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1035 rwTransaction.delete(datastore, path.getParent());
1036 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1037 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1040 final OrderedLeafSetNode<?> readLeafList =
1041 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1042 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1043 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1045 rwTransaction.delete(datastore, path.getParent());
1046 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1047 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1053 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1056 if (schemaNode instanceof ListSchemaNode) {
1057 final OrderedMapNode readList =
1058 (OrderedMapNode) this.readConfigurationData(path.getParent());
1059 if (readList == null || readList.getValue().isEmpty()) {
1060 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1062 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1066 final OrderedLeafSetNode<?> readLeafList =
1067 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1068 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1069 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1071 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1072 readLeafList, true);
1077 if (schemaNode instanceof ListSchemaNode) {
1078 final OrderedMapNode readList =
1079 (OrderedMapNode) this.readConfigurationData(path.getParent());
1080 if (readList == null || readList.getValue().isEmpty()) {
1081 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1083 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1087 final OrderedLeafSetNode<?> readLeafList =
1088 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1089 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1090 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1092 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1093 readLeafList, false);
1098 throw new RestconfDocumentedException(
1099 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1104 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1105 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1106 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1107 final boolean before) {
1108 tx.delete(datastore, path.getParent());
1109 final InstanceIdentifierContext<?> instanceIdentifier =
1110 ControllerContext.getInstance().toInstanceIdentifier(point);
1112 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1113 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1122 final NormalizedNode<?, ?> emptySubtree =
1123 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1124 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1125 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1126 if (index2 == index1) {
1127 simplePut(datastore, path, tx, schemaContext, payload);
1129 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1130 tx.put(datastore, childPath, nodeChild);
1135 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1136 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1137 final String point, final OrderedMapNode readList, final boolean before) {
1138 tx.delete(datastore, path.getParent());
1139 final InstanceIdentifierContext<?> instanceIdentifier =
1140 ControllerContext.getInstance().toInstanceIdentifier(point);
1142 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1143 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1152 final NormalizedNode<?, ?> emptySubtree =
1153 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1154 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1155 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1156 if (index2 == index1) {
1157 simplePut(datastore, path, tx, schemaContext, payload);
1159 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1160 tx.put(datastore, childPath, mapEntryNode);
1165 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1166 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1167 if (payload instanceof MapNode) {
1168 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1169 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1170 ensureParentsByMerge(datastore, path, tx, schemaContext);
1171 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1172 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1173 tx.put(datastore, childPath, child);
1176 simplePut(datastore, path, tx, schemaContext, payload);
1180 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1181 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1182 ensureParentsByMerge(datastore, path, tx, schemaContext);
1183 tx.put(datastore, path, payload);
1186 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1187 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1188 final YangInstanceIdentifier path) {
1189 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1190 checkItemExists(readWriteTransaction, datastore, path);
1191 readWriteTransaction.delete(datastore, path);
1192 return readWriteTransaction.submit();
1195 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1196 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1197 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1198 tx.delete(datastore, path);
1201 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1202 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1203 final SchemaContext schemaContext) {
1204 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1205 ensureParentsByMerge(datastore, path, tx, schemaContext);
1207 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1208 // OpenDaylight should not change it.
1209 tx.merge(datastore, path, payload);
1212 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1213 this.domDataBroker = domDataBroker;
1216 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1217 checkPreconditions();
1219 if (listener.isListening()) {
1223 final SchemaPath path = listener.getSchemaPath();
1224 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1225 .registerNotificationListener(listener, path);
1227 listener.setRegistration(registration);
1230 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1231 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1232 final SchemaContext schemaContext) {
1233 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1234 YangInstanceIdentifier rootNormalizedPath = null;
1236 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1238 while (it.hasNext()) {
1239 final PathArgument pathArgument = it.next();
1240 if (rootNormalizedPath == null) {
1241 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1245 normalizedPathWithoutChildArgs.add(pathArgument);
1249 if (normalizedPathWithoutChildArgs.isEmpty()) {
1253 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1255 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1256 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1257 tx.merge(store, rootNormalizedPath, parentStructure);
1260 private static final class PatchStatusContextHelper {
1261 PatchStatusContext status;
1263 public PatchStatusContext getStatus() {
1267 public void setStatus(final PatchStatusContext status) {
1268 this.status = status;