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.streams.listeners.ListenerAdapter;
44 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
45 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
46 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
47 import org.opendaylight.restconf.common.errors.RestconfError;
48 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
49 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
50 import org.opendaylight.yangtools.concepts.ListenerRegistration;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.common.RpcError;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
56 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
57 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
59 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
65 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
67 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
68 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
69 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
70 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
71 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
72 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
73 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
74 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
77 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
78 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
79 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
80 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 public class BrokerFacade {
85 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
86 private static final BrokerFacade INSTANCE = new BrokerFacade();
88 private volatile DOMRpcService rpcService;
90 private DOMDataBroker domDataBroker;
91 private DOMNotificationService domNotification;
93 private BrokerFacade() {}
95 public void setRpcService(final DOMRpcService router) {
96 this.rpcService = router;
99 public void setDomNotificationService(final DOMNotificationService domNotification) {
100 this.domNotification = domNotification;
103 public static BrokerFacade getInstance() {
104 return BrokerFacade.INSTANCE;
107 private void checkPreconditions() {
108 if (this.domDataBroker == null) {
109 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
114 * Read config data by path.
120 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
121 return readConfigurationData(path, null);
125 * Read config data by path.
130 * value of with-defaults parameter
133 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
134 checkPreconditions();
135 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
136 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
141 * Read config data from mount point by path.
144 * mount point for reading data
149 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
150 final YangInstanceIdentifier path) {
151 return readConfigurationData(mountPoint, path, null);
155 * Read config data from mount point by path.
158 * mount point for reading data
162 * value of with-defaults parameter
165 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
166 final String withDefa) {
167 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
168 if (domDataBrokerService.isPresent()) {
169 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
170 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
173 final String errMsg = "DOM data broker service isn't available for mount point " + path;
175 throw new RestconfDocumentedException(errMsg);
179 * Read operational data by path.
185 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
186 checkPreconditions();
188 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
189 return readDataViaTransaction(tx, OPERATIONAL, path);
194 * Read operational data from mount point by path.
197 * mount point for reading data
202 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
203 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
204 if (domDataBrokerService.isPresent()) {
205 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
206 return readDataViaTransaction(tx, OPERATIONAL, path);
209 final String errMsg = "DOM data broker service isn't available for mount point " + path;
211 throw new RestconfDocumentedException(errMsg);
215 * <b>PUT configuration data</b>
218 * Prepare result(status) for PUT operation and PUT data via transaction.
219 * Return wrapped status and future from PUT.
221 * @param globalSchema
222 * used by merge parents (if contains list)
231 * @return wrapper of status and future of PUT
233 public PutResult commitConfigurationDataPut(
234 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
235 final String insert, final String point) {
236 Preconditions.checkNotNull(globalSchema);
237 Preconditions.checkNotNull(path);
238 Preconditions.checkNotNull(payload);
240 checkPreconditions();
242 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
243 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
245 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
246 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
247 return new PutResult(status, future);
251 * <b>PUT configuration data (Mount point)</b>
254 * Prepare result(status) for PUT operation and PUT data via transaction.
255 * Return wrapped status and future from PUT.
258 * mount point for getting transaction for operation and schema
259 * context for merging parents(if contains list)
268 * @return wrapper of status and future of PUT
270 public PutResult commitMountPointDataPut(
271 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
272 final String insert, final String point) {
273 Preconditions.checkNotNull(mountPoint);
274 Preconditions.checkNotNull(path);
275 Preconditions.checkNotNull(payload);
277 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
278 if (domDataBrokerService.isPresent()) {
279 final DOMDataReadWriteTransaction newReadWriteTransaction =
280 domDataBrokerService.get().newReadWriteTransaction();
281 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
282 ? Status.OK : Status.CREATED;
283 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
284 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
286 return new PutResult(status, future);
288 final String errMsg = "DOM data broker service isn't available for mount point " + path;
290 throw new RestconfDocumentedException(errMsg);
293 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
295 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
297 // get new transaction and schema context on server or on mounted device
298 final SchemaContext schemaContext;
299 final DOMDataReadWriteTransaction patchTransaction;
300 if (mountPoint == null) {
301 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
302 patchTransaction = this.domDataBroker.newReadWriteTransaction();
304 schemaContext = mountPoint.getSchemaContext();
306 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
308 if (optional.isPresent()) {
309 patchTransaction = optional.get().newReadWriteTransaction();
311 // if mount point does not have broker it is not possible to continue and global error is reported
312 LOG.error("Http Patch {} has failed - device {} does not support broker service",
313 patchContext.getPatchId(), mountPoint.getIdentifier());
314 return new PatchStatusContext(
315 patchContext.getPatchId(),
318 ImmutableList.of(new RestconfError(
319 ErrorType.APPLICATION,
320 ErrorTag.OPERATION_FAILED,
321 "DOM data broker service isn't available for mount point "
322 + mountPoint.getIdentifier()))
327 final List<PatchStatusEntity> editCollection = new ArrayList<>();
328 List<RestconfError> editErrors;
329 boolean withoutError = true;
331 for (final PatchEntity patchEntity : patchContext.getData()) {
332 final PatchEditOperation operation = patchEntity.getOperation();
337 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
338 patchEntity.getNode(), schemaContext);
339 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
340 } catch (final RestconfDocumentedException e) {
341 LOG.error("Error call http Patch operation {} on target {}",
343 patchEntity.getTargetNode().toString());
345 editErrors = new ArrayList<>();
346 editErrors.addAll(e.getErrors());
347 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
348 withoutError = false;
355 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
356 .getTargetNode(), patchEntity.getNode(), schemaContext);
357 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
358 } catch (final RestconfDocumentedException e) {
359 LOG.error("Error call http Patch operation {} on target {}",
361 patchEntity.getTargetNode().toString());
363 editErrors = new ArrayList<>();
364 editErrors.addAll(e.getErrors());
365 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
366 withoutError = false;
373 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
375 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
376 } catch (final RestconfDocumentedException e) {
377 LOG.error("Error call http Patch operation {} on target {}",
379 patchEntity.getTargetNode().toString());
381 editErrors = new ArrayList<>();
382 editErrors.addAll(e.getErrors());
383 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
384 withoutError = false;
391 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
393 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
394 } catch (final RestconfDocumentedException e) {
395 LOG.error("Error call http Patch operation {} on target {}",
397 patchEntity.getTargetNode().toString());
399 editErrors = new ArrayList<>();
400 editErrors.addAll(e.getErrors());
401 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
402 withoutError = false;
409 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
410 patchEntity.getNode(), schemaContext);
411 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
412 } catch (final RestconfDocumentedException e) {
413 LOG.error("Error call http Patch operation {} on target {}",
415 patchEntity.getTargetNode().toString());
417 editErrors = new ArrayList<>();
418 editErrors.addAll(e.getErrors());
419 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
420 withoutError = false;
425 LOG.error("Unsupported http Patch operation {} on target {}",
427 patchEntity.getTargetNode().toString());
432 // if errors then cancel transaction and return error status
434 patchTransaction.cancel();
435 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
438 // if no errors commit transaction
439 final CountDownLatch waiter = new CountDownLatch(1);
440 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
441 final PatchStatusContextHelper status = new PatchStatusContextHelper();
443 Futures.addCallback(future, new FutureCallback<Void>() {
445 public void onSuccess(@Nullable final Void result) {
446 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
452 public void onFailure(final Throwable throwable) {
453 // if commit failed it is global error
454 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
455 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
456 false, ImmutableList.of(
457 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
463 return status.getStatus();
466 // POST configuration
467 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
468 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
469 final String insert, final String point) {
470 checkPreconditions();
471 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
472 globalSchema, insert, point);
475 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
476 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
477 final String insert, final String point) {
478 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
479 if (domDataBrokerService.isPresent()) {
480 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
481 payload, mountPoint.getSchemaContext(), insert, point);
483 final String errMsg = "DOM data broker service isn't available for mount point " + path;
485 throw new RestconfDocumentedException(errMsg);
488 // DELETE configuration
489 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
490 final YangInstanceIdentifier path) {
491 checkPreconditions();
492 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
495 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
496 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
497 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
498 if (domDataBrokerService.isPresent()) {
499 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
501 final String errMsg = "DOM data broker service isn't available for mount point " + path;
503 throw new RestconfDocumentedException(errMsg);
507 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
508 final NormalizedNode<?, ?> input) {
509 checkPreconditions();
510 if (this.rpcService == null) {
511 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
513 LOG.trace("Invoke RPC {} with input: {}", type, input);
514 return this.rpcService.invokeRpc(type, input);
517 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
518 final ListenerAdapter listener) {
519 checkPreconditions();
521 if (listener.isListening()) {
525 final YangInstanceIdentifier path = listener.getPath();
526 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
527 datastore, path, listener, scope);
529 listener.setRegistration(registration);
532 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
533 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
534 return readDataViaTransaction(transaction, datastore, path, null);
537 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
538 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
539 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
542 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
543 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
544 prepareDataByParamWithDef(optional.get(), path, withDefa);
545 } catch (ReadFailedException e) {
546 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
547 for (final RpcError error : e.getErrorList()) {
548 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
549 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
550 throw new RestconfDocumentedException(
553 ErrorTag.RESOURCE_DENIED_TRANSPORT);
556 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
560 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
561 final YangInstanceIdentifier path, final String withDefa) {
571 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
574 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
575 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
576 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
577 if (result instanceof ContainerNode) {
578 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
579 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
580 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
581 return builder.build();
584 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
585 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
586 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
587 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
588 return builder.build();
591 private void buildMapEntryBuilder(
592 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
593 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
594 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
595 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
596 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
597 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
598 if (child instanceof ContainerNode) {
599 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
600 Builders.containerBuilder((ContainerSchemaNode) childSchema);
601 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
602 builder.withChild(childBuilder.build());
603 } else if (child instanceof MapNode) {
604 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
605 Builders.mapBuilder((ListSchemaNode) childSchema);
606 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
607 ((ListSchemaNode) childSchema).getKeyDefinition());
608 builder.withChild(childBuilder.build());
609 } else if (child instanceof LeafNode) {
610 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
611 final String nodeVal = ((LeafNode<String>) child).getValue();
612 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
613 Builders.leafBuilder((LeafSchemaNode) childSchema);
614 if (keys.contains(child.getNodeType())) {
615 leafBuilder.withValue(((LeafNode<?>) child).getValue());
616 builder.withChild(leafBuilder.build());
619 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
620 leafBuilder.withValue(((LeafNode<?>) child).getValue());
621 builder.withChild(leafBuilder.build());
624 if (defaultVal != null && defaultVal.equals(nodeVal)) {
625 leafBuilder.withValue(((LeafNode<?>) child).getValue());
626 builder.withChild(leafBuilder.build());
634 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
635 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
636 final List<QName> keys) {
637 for (final MapEntryNode mapEntryNode : result.getValue()) {
638 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
639 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
640 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
641 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
642 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
643 builder.withChild(mapEntryBuilder.build());
647 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
648 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
649 final YangInstanceIdentifier actualPath, final boolean trim) {
650 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
651 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
652 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
653 if (child instanceof ContainerNode) {
654 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
655 Builders.containerBuilder((ContainerSchemaNode) childSchema);
656 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
657 builder.withChild(builderChild.build());
658 } else if (child instanceof MapNode) {
659 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
660 Builders.mapBuilder((ListSchemaNode) childSchema);
661 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
662 ((ListSchemaNode) childSchema).getKeyDefinition());
663 builder.withChild(childBuilder.build());
664 } else if (child instanceof LeafNode) {
665 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
666 final String nodeVal = ((LeafNode<String>) child).getValue();
667 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
668 Builders.leafBuilder((LeafSchemaNode) childSchema);
670 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
671 leafBuilder.withValue(((LeafNode<?>) child).getValue());
672 builder.withChild(leafBuilder.build());
675 if (defaultVal != null && defaultVal.equals(nodeVal)) {
676 leafBuilder.withValue(((LeafNode<?>) child).getValue());
677 builder.withChild(leafBuilder.build());
685 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
687 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
688 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
689 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
690 final String insert, final String point) {
691 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
692 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
693 return rwTransaction.submit();
697 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
699 private void postDataWithinTransaction(
700 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
701 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
702 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
703 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
706 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
707 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
708 final SchemaContext schemaContext, final String insert, final String point) {
709 if (insert == null) {
710 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
714 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
715 checkItemDoesNotExists(rwTransaction, datastore, path);
718 if (schemaNode instanceof ListSchemaNode) {
719 final OrderedMapNode readList =
720 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
721 if (readList == null || readList.getValue().isEmpty()) {
722 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
724 rwTransaction.delete(datastore, path.getParent().getParent());
725 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
726 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
730 final OrderedLeafSetNode<?> readLeafList =
731 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
732 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
733 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
735 rwTransaction.delete(datastore, path.getParent());
736 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
737 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
743 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
746 if (schemaNode instanceof ListSchemaNode) {
747 final OrderedMapNode readList =
748 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
749 if (readList == null || readList.getValue().isEmpty()) {
750 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
752 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
757 final OrderedLeafSetNode<?> readLeafList =
758 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
759 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
760 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
762 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
768 if (schemaNode instanceof ListSchemaNode) {
769 final OrderedMapNode readList =
770 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
771 if (readList == null || readList.getValue().isEmpty()) {
772 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
774 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
779 final OrderedLeafSetNode<?> readLeafList =
780 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
781 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
782 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
784 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
785 readLeafList, false);
790 throw new RestconfDocumentedException(
791 "Used bad value of insert parameter. Possible values are first, last, before or after, "
792 + "but was: " + insert);
796 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
797 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
798 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
799 final boolean before) {
800 rwTransaction.delete(datastore, path.getParent().getParent());
801 final InstanceIdentifierContext<?> instanceIdentifier =
802 ControllerContext.getInstance().toInstanceIdentifier(point);
803 int lastItemPosition = 0;
804 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
805 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
813 int lastInsertedPosition = 0;
814 final NormalizedNode<?, ?> emptySubtree =
815 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
816 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
817 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
818 if (lastInsertedPosition == lastItemPosition) {
819 checkItemDoesNotExists(rwTransaction, datastore, path);
820 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
822 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
823 checkItemDoesNotExists(rwTransaction, datastore, childPath);
824 rwTransaction.put(datastore, childPath, nodeChild);
825 lastInsertedPosition++;
829 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
830 final LogicalDatastoreType datastore,
831 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
832 final String point, final MapNode readList, final boolean before) {
833 rwTransaction.delete(datastore, path.getParent().getParent());
834 final InstanceIdentifierContext<?> instanceIdentifier =
835 ControllerContext.getInstance().toInstanceIdentifier(point);
836 int lastItemPosition = 0;
837 for (final MapEntryNode mapEntryNode : readList.getValue()) {
838 if (mapEntryNode.getIdentifier()
839 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
847 int lastInsertedPosition = 0;
848 final NormalizedNode<?, ?> emptySubtree =
849 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
850 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
851 for (final MapEntryNode mapEntryNode : readList.getValue()) {
852 if (lastInsertedPosition == lastItemPosition) {
853 checkItemDoesNotExists(rwTransaction, datastore, path);
854 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
856 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
857 checkItemDoesNotExists(rwTransaction, datastore, childPath);
858 rwTransaction.put(datastore, childPath, mapEntryNode);
859 lastInsertedPosition++;
863 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
864 final YangInstanceIdentifier parent = path.getParent();
865 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
866 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
868 if (dataSchemaNode instanceof ListSchemaNode) {
869 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
870 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
872 return dataSchemaNode;
874 if (dataSchemaNode instanceof LeafListSchemaNode) {
875 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
876 throw new RestconfDocumentedException(
877 "Insert parameter can be used only with ordered-by user leaf-list.");
879 return dataSchemaNode;
881 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
884 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
885 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
886 final SchemaContext schemaContext) {
887 final Collection<? extends NormalizedNode<?, ?>> children;
888 if (payload instanceof MapNode) {
889 children = ((MapNode) payload).getValue();
890 } else if (payload instanceof LeafSetNode) {
891 children = ((LeafSetNode<?>) payload).getValue();
893 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
897 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
898 if (children.isEmpty()) {
899 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
900 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
904 // Kick off batch existence check first...
905 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
907 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
908 // result of the existence checks...
909 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
910 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
911 for (final NormalizedNode<?, ?> child : children) {
912 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
913 // as that would allow us to skip the existence checks
914 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
917 // ... finally collect existence checks and abort the transaction if any of them failed.
918 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
920 failure = check.getFailure();
921 } catch (InterruptedException e) {
922 rwTransaction.cancel();
923 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
926 if (failure != null) {
927 rwTransaction.cancel();
928 final ReadFailedException e = failure.getValue();
930 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
931 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
934 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
939 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
940 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
941 final SchemaContext schemaContext) {
942 checkItemDoesNotExists(rwTransaction, datastore, path);
943 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
944 rwTransaction.put(datastore, path, payload);
947 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
948 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
950 return rwTransaction.exists(store, path).checkedGet();
951 } catch (ReadFailedException e) {
952 rwTransaction.cancel();
953 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
954 e, e.getErrorList());
959 * Check if item already exists. Throws error if it does NOT already exist.
960 * @param rwTransaction Current transaction
961 * @param store Used datastore
962 * @param path Path to item to verify its existence
964 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
965 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
966 if (!doesItemExist(rwTransaction, store, path)) {
967 final String errMsg = "Operation via Restconf was not executed because data does not exist";
968 LOG.trace("{}:{}", errMsg, path);
969 rwTransaction.cancel();
970 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
971 ErrorTag.DATA_MISSING);
976 * Check if item does NOT already exist. Throws error if it already exists.
977 * @param rwTransaction Current transaction
978 * @param store Used datastore
979 * @param path Path to item to verify its existence
981 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
982 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
983 if (doesItemExist(rwTransaction, store, path)) {
984 final String errMsg = "Operation via Restconf was not executed because data already exists";
985 LOG.trace("{}:{}", errMsg, path);
986 rwTransaction.cancel();
987 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
988 ErrorTag.DATA_EXISTS);
993 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1000 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1001 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1002 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1003 final String insert, final String point) {
1004 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1005 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1006 return readWriteTransaction.submit();
1010 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1012 private void putDataWithinTransaction(
1013 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1014 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1015 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1016 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1019 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1020 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1021 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1022 final String insert, final String point) {
1023 if (insert == null) {
1024 makePut(rwTransaction, datastore, path, payload, schemaContext);
1028 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1029 checkItemDoesNotExists(rwTransaction, datastore, path);
1032 if (schemaNode instanceof ListSchemaNode) {
1033 final OrderedMapNode readList =
1034 (OrderedMapNode) this.readConfigurationData(path.getParent());
1035 if (readList == null || readList.getValue().isEmpty()) {
1036 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1038 rwTransaction.delete(datastore, path.getParent());
1039 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1040 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1043 final OrderedLeafSetNode<?> readLeafList =
1044 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1045 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1046 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1048 rwTransaction.delete(datastore, path.getParent());
1049 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1050 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1056 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1059 if (schemaNode instanceof ListSchemaNode) {
1060 final OrderedMapNode readList =
1061 (OrderedMapNode) this.readConfigurationData(path.getParent());
1062 if (readList == null || readList.getValue().isEmpty()) {
1063 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1065 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1069 final OrderedLeafSetNode<?> readLeafList =
1070 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1071 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1072 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1074 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1075 readLeafList, true);
1080 if (schemaNode instanceof ListSchemaNode) {
1081 final OrderedMapNode readList =
1082 (OrderedMapNode) this.readConfigurationData(path.getParent());
1083 if (readList == null || readList.getValue().isEmpty()) {
1084 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1086 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1090 final OrderedLeafSetNode<?> readLeafList =
1091 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1092 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1093 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1095 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1096 readLeafList, false);
1101 throw new RestconfDocumentedException(
1102 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1107 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1108 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1109 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1110 final boolean before) {
1111 tx.delete(datastore, path.getParent());
1112 final InstanceIdentifierContext<?> instanceIdentifier =
1113 ControllerContext.getInstance().toInstanceIdentifier(point);
1115 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1116 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1125 final NormalizedNode<?, ?> emptySubtree =
1126 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1127 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1128 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1129 if (index2 == index1) {
1130 simplePut(datastore, path, tx, schemaContext, payload);
1132 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1133 tx.put(datastore, childPath, nodeChild);
1138 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1139 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1140 final String point, final OrderedMapNode readList, final boolean before) {
1141 tx.delete(datastore, path.getParent());
1142 final InstanceIdentifierContext<?> instanceIdentifier =
1143 ControllerContext.getInstance().toInstanceIdentifier(point);
1145 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1146 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1155 final NormalizedNode<?, ?> emptySubtree =
1156 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1157 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1158 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1159 if (index2 == index1) {
1160 simplePut(datastore, path, tx, schemaContext, payload);
1162 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1163 tx.put(datastore, childPath, mapEntryNode);
1168 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1169 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1170 if (payload instanceof MapNode) {
1171 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1172 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1173 ensureParentsByMerge(datastore, path, tx, schemaContext);
1174 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1175 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1176 tx.put(datastore, childPath, child);
1179 simplePut(datastore, path, tx, schemaContext, payload);
1183 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1184 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1185 ensureParentsByMerge(datastore, path, tx, schemaContext);
1186 tx.put(datastore, path, payload);
1189 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1190 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1191 final YangInstanceIdentifier path) {
1192 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1193 checkItemExists(readWriteTransaction, datastore, path);
1194 readWriteTransaction.delete(datastore, path);
1195 return readWriteTransaction.submit();
1198 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1199 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1200 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1201 tx.delete(datastore, path);
1204 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1205 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1206 final SchemaContext schemaContext) {
1207 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1208 ensureParentsByMerge(datastore, path, tx, schemaContext);
1210 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1211 // OpenDaylight should not change it.
1212 tx.merge(datastore, path, payload);
1215 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1216 this.domDataBroker = domDataBroker;
1219 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1220 checkPreconditions();
1222 if (listener.isListening()) {
1226 final SchemaPath path = listener.getSchemaPath();
1227 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1228 .registerNotificationListener(listener, path);
1230 listener.setRegistration(registration);
1233 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1234 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1235 final SchemaContext schemaContext) {
1236 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1237 YangInstanceIdentifier rootNormalizedPath = null;
1239 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1241 while (it.hasNext()) {
1242 final PathArgument pathArgument = it.next();
1243 if (rootNormalizedPath == null) {
1244 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1248 normalizedPathWithoutChildArgs.add(pathArgument);
1252 if (normalizedPathWithoutChildArgs.isEmpty()) {
1256 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1258 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1259 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1260 tx.merge(store, rootNormalizedPath, parentStructure);
1263 private static final class PatchStatusContextHelper {
1264 PatchStatusContext status;
1266 public PatchStatusContext getStatus() {
1270 public void setStatus(final PatchStatusContext status) {
1271 this.status = status;