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 com.google.common.util.concurrent.MoreExecutors;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map.Entry;
25 import java.util.concurrent.CountDownLatch;
26 import javax.annotation.Nullable;
27 import javax.ws.rs.core.Response.Status;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
38 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
39 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
40 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
43 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
44 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
45 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
46 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
47 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
48 import org.opendaylight.restconf.common.errors.RestconfError;
49 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
50 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
51 import org.opendaylight.restconf.common.patch.PatchContext;
52 import org.opendaylight.restconf.common.patch.PatchEditOperation;
53 import org.opendaylight.restconf.common.patch.PatchEntity;
54 import org.opendaylight.restconf.common.patch.PatchStatusContext;
55 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
56 import org.opendaylight.yangtools.concepts.ListenerRegistration;
57 import org.opendaylight.yangtools.yang.common.QName;
58 import org.opendaylight.yangtools.yang.common.RpcError;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
63 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
65 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
68 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
69 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
70 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
73 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
74 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
75 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
76 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
78 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
79 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
80 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
81 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
82 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
85 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
86 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
87 import org.slf4j.Logger;
88 import org.slf4j.LoggerFactory;
90 public class BrokerFacade {
91 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
92 private static final BrokerFacade INSTANCE = new BrokerFacade();
94 private volatile DOMRpcService rpcService;
96 private DOMDataBroker domDataBroker;
97 private DOMNotificationService domNotification;
99 private BrokerFacade() {}
101 public void setRpcService(final DOMRpcService router) {
102 this.rpcService = router;
105 public void setDomNotificationService(final DOMNotificationService domNotification) {
106 this.domNotification = domNotification;
109 public static BrokerFacade getInstance() {
110 return BrokerFacade.INSTANCE;
113 private void checkPreconditions() {
114 if (this.domDataBroker == null) {
115 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
120 * Read config data by path.
126 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
127 return readConfigurationData(path, null);
131 * Read config data by path.
136 * value of with-defaults parameter
139 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
140 checkPreconditions();
141 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
142 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
147 * Read config data from mount point by path.
150 * mount point for reading data
155 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
156 final YangInstanceIdentifier path) {
157 return readConfigurationData(mountPoint, path, null);
161 * Read config data from mount point by path.
164 * mount point for reading data
168 * value of with-defaults parameter
171 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
172 final String withDefa) {
173 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
174 if (domDataBrokerService.isPresent()) {
175 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
176 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
179 final String errMsg = "DOM data broker service isn't available for mount point " + path;
181 throw new RestconfDocumentedException(errMsg);
185 * Read operational data by path.
191 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
192 checkPreconditions();
194 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
195 return readDataViaTransaction(tx, OPERATIONAL, path);
200 * Read operational data from mount point by path.
203 * mount point for reading data
208 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
209 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
210 if (domDataBrokerService.isPresent()) {
211 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
212 return readDataViaTransaction(tx, OPERATIONAL, path);
215 final String errMsg = "DOM data broker service isn't available for mount point " + path;
217 throw new RestconfDocumentedException(errMsg);
221 * <b>PUT configuration data</b>
224 * Prepare result(status) for PUT operation and PUT data via transaction.
225 * Return wrapped status and future from PUT.
227 * @param globalSchema
228 * used by merge parents (if contains list)
237 * @return wrapper of status and future of PUT
239 public PutResult commitConfigurationDataPut(
240 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
241 final String insert, final String point) {
242 Preconditions.checkNotNull(globalSchema);
243 Preconditions.checkNotNull(path);
244 Preconditions.checkNotNull(payload);
246 checkPreconditions();
248 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
249 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
251 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
252 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
253 return new PutResult(status, future);
257 * <b>PUT configuration data (Mount point)</b>
260 * Prepare result(status) for PUT operation and PUT data via transaction.
261 * Return wrapped status and future from PUT.
264 * mount point for getting transaction for operation and schema
265 * context for merging parents(if contains list)
274 * @return wrapper of status and future of PUT
276 public PutResult commitMountPointDataPut(
277 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
278 final String insert, final String point) {
279 Preconditions.checkNotNull(mountPoint);
280 Preconditions.checkNotNull(path);
281 Preconditions.checkNotNull(payload);
283 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
284 if (domDataBrokerService.isPresent()) {
285 final DOMDataReadWriteTransaction newReadWriteTransaction =
286 domDataBrokerService.get().newReadWriteTransaction();
287 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
288 ? Status.OK : Status.CREATED;
289 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
290 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
292 return new PutResult(status, future);
294 final String errMsg = "DOM data broker service isn't available for mount point " + path;
296 throw new RestconfDocumentedException(errMsg);
299 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
301 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
303 // get new transaction and schema context on server or on mounted device
304 final SchemaContext schemaContext;
305 final DOMDataReadWriteTransaction patchTransaction;
306 if (mountPoint == null) {
307 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
308 patchTransaction = this.domDataBroker.newReadWriteTransaction();
310 schemaContext = mountPoint.getSchemaContext();
312 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
314 if (optional.isPresent()) {
315 patchTransaction = optional.get().newReadWriteTransaction();
317 // if mount point does not have broker it is not possible to continue and global error is reported
318 LOG.error("Http Patch {} has failed - device {} does not support broker service",
319 patchContext.getPatchId(), mountPoint.getIdentifier());
320 return new PatchStatusContext(
321 patchContext.getPatchId(),
324 ImmutableList.of(new RestconfError(
325 ErrorType.APPLICATION,
326 ErrorTag.OPERATION_FAILED,
327 "DOM data broker service isn't available for mount point "
328 + mountPoint.getIdentifier()))
333 final List<PatchStatusEntity> editCollection = new ArrayList<>();
334 List<RestconfError> editErrors;
335 boolean withoutError = true;
337 for (final PatchEntity patchEntity : patchContext.getData()) {
338 final PatchEditOperation operation = patchEntity.getOperation();
343 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
344 patchEntity.getNode(), schemaContext);
345 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
346 } catch (final RestconfDocumentedException e) {
347 LOG.error("Error call http Patch operation {} on target {}",
349 patchEntity.getTargetNode().toString());
351 editErrors = new ArrayList<>();
352 editErrors.addAll(e.getErrors());
353 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
354 withoutError = false;
361 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
362 .getTargetNode(), patchEntity.getNode(), schemaContext);
363 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
364 } catch (final RestconfDocumentedException e) {
365 LOG.error("Error call http Patch operation {} on target {}",
367 patchEntity.getTargetNode().toString());
369 editErrors = new ArrayList<>();
370 editErrors.addAll(e.getErrors());
371 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
372 withoutError = false;
379 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
381 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
382 } catch (final RestconfDocumentedException e) {
383 LOG.error("Error call http Patch operation {} on target {}",
385 patchEntity.getTargetNode().toString());
387 editErrors = new ArrayList<>();
388 editErrors.addAll(e.getErrors());
389 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
390 withoutError = false;
397 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
399 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
400 } catch (final RestconfDocumentedException e) {
401 LOG.error("Error call http Patch operation {} on target {}",
403 patchEntity.getTargetNode().toString());
405 editErrors = new ArrayList<>();
406 editErrors.addAll(e.getErrors());
407 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
408 withoutError = false;
415 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
416 patchEntity.getNode(), schemaContext);
417 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
418 } catch (final RestconfDocumentedException e) {
419 LOG.error("Error call http Patch operation {} on target {}",
421 patchEntity.getTargetNode().toString());
423 editErrors = new ArrayList<>();
424 editErrors.addAll(e.getErrors());
425 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
426 withoutError = false;
431 LOG.error("Unsupported http Patch operation {} on target {}",
433 patchEntity.getTargetNode().toString());
438 // if errors then cancel transaction and return error status
440 patchTransaction.cancel();
441 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
444 // if no errors commit transaction
445 final CountDownLatch waiter = new CountDownLatch(1);
446 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
447 final PatchStatusContextHelper status = new PatchStatusContextHelper();
449 Futures.addCallback(future, new FutureCallback<Void>() {
451 public void onSuccess(@Nullable final Void result) {
452 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
458 public void onFailure(final Throwable throwable) {
459 // if commit failed it is global error
460 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
461 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
462 false, ImmutableList.of(
463 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
466 }, MoreExecutors.directExecutor());
469 return status.getStatus();
472 // POST configuration
473 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
474 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
475 final String insert, final String point) {
476 checkPreconditions();
477 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
478 globalSchema, insert, point);
481 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
482 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
483 final String insert, final String point) {
484 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
485 if (domDataBrokerService.isPresent()) {
486 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
487 payload, mountPoint.getSchemaContext(), insert, point);
489 final String errMsg = "DOM data broker service isn't available for mount point " + path;
491 throw new RestconfDocumentedException(errMsg);
494 // DELETE configuration
495 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
496 final YangInstanceIdentifier path) {
497 checkPreconditions();
498 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
501 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
502 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
503 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
504 if (domDataBrokerService.isPresent()) {
505 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
507 final String errMsg = "DOM data broker service isn't available for mount point " + path;
509 throw new RestconfDocumentedException(errMsg);
513 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
514 final NormalizedNode<?, ?> input) {
515 checkPreconditions();
516 if (this.rpcService == null) {
517 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
519 LOG.trace("Invoke RPC {} with input: {}", type, input);
520 return this.rpcService.invokeRpc(type, input);
523 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
524 final ListenerAdapter listener) {
525 checkPreconditions();
527 if (listener.isListening()) {
531 final YangInstanceIdentifier path = listener.getPath();
532 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
533 datastore, path, listener, scope);
535 listener.setRegistration(registration);
538 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
539 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
540 return readDataViaTransaction(transaction, datastore, path, null);
543 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
544 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
545 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
548 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
549 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
550 prepareDataByParamWithDef(optional.get(), path, withDefa);
551 } catch (ReadFailedException e) {
552 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
553 for (final RpcError error : e.getErrorList()) {
554 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
555 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
556 throw new RestconfDocumentedException(
559 ErrorTag.RESOURCE_DENIED_TRANSPORT);
562 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
566 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
567 final YangInstanceIdentifier path, final String withDefa) {
577 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
580 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
581 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
582 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
583 if (result instanceof ContainerNode) {
584 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
585 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
586 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
587 return builder.build();
590 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
591 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
592 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
593 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
594 return builder.build();
597 private void buildMapEntryBuilder(
598 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
599 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
600 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
601 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
602 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
603 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
604 if (child instanceof ContainerNode) {
605 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
606 Builders.containerBuilder((ContainerSchemaNode) childSchema);
607 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
608 builder.withChild(childBuilder.build());
609 } else if (child instanceof MapNode) {
610 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
611 Builders.mapBuilder((ListSchemaNode) childSchema);
612 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
613 ((ListSchemaNode) childSchema).getKeyDefinition());
614 builder.withChild(childBuilder.build());
615 } else if (child instanceof LeafNode) {
616 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
617 final String nodeVal = ((LeafNode<String>) child).getValue();
618 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
619 Builders.leafBuilder((LeafSchemaNode) childSchema);
620 if (keys.contains(child.getNodeType())) {
621 leafBuilder.withValue(((LeafNode<?>) child).getValue());
622 builder.withChild(leafBuilder.build());
625 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
626 leafBuilder.withValue(((LeafNode<?>) child).getValue());
627 builder.withChild(leafBuilder.build());
630 if (defaultVal != null && defaultVal.equals(nodeVal)) {
631 leafBuilder.withValue(((LeafNode<?>) child).getValue());
632 builder.withChild(leafBuilder.build());
640 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
641 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
642 final List<QName> keys) {
643 for (final MapEntryNode mapEntryNode : result.getValue()) {
644 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
645 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
646 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
647 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
648 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
649 builder.withChild(mapEntryBuilder.build());
653 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
654 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
655 final YangInstanceIdentifier actualPath, final boolean trim) {
656 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
657 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
658 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
659 if (child instanceof ContainerNode) {
660 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
661 Builders.containerBuilder((ContainerSchemaNode) childSchema);
662 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
663 builder.withChild(builderChild.build());
664 } else if (child instanceof MapNode) {
665 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
666 Builders.mapBuilder((ListSchemaNode) childSchema);
667 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
668 ((ListSchemaNode) childSchema).getKeyDefinition());
669 builder.withChild(childBuilder.build());
670 } else if (child instanceof LeafNode) {
671 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
672 final String nodeVal = ((LeafNode<String>) child).getValue();
673 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
674 Builders.leafBuilder((LeafSchemaNode) childSchema);
676 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
677 leafBuilder.withValue(((LeafNode<?>) child).getValue());
678 builder.withChild(leafBuilder.build());
681 if (defaultVal != null && defaultVal.equals(nodeVal)) {
682 leafBuilder.withValue(((LeafNode<?>) child).getValue());
683 builder.withChild(leafBuilder.build());
691 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
693 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
694 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
695 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
696 final String insert, final String point) {
697 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
698 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
699 return rwTransaction.submit();
703 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
705 private void postDataWithinTransaction(
706 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
707 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
708 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
709 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
712 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
713 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
714 final SchemaContext schemaContext, final String insert, final String point) {
715 if (insert == null) {
716 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
720 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
721 checkItemDoesNotExists(rwTransaction, datastore, path);
724 if (schemaNode instanceof ListSchemaNode) {
725 final OrderedMapNode readList =
726 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
727 if (readList == null || readList.getValue().isEmpty()) {
728 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
730 rwTransaction.delete(datastore, path.getParent().getParent());
731 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
732 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
736 final OrderedLeafSetNode<?> readLeafList =
737 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
738 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
739 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
741 rwTransaction.delete(datastore, path.getParent());
742 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
743 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
749 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
752 if (schemaNode instanceof ListSchemaNode) {
753 final OrderedMapNode readList =
754 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
755 if (readList == null || readList.getValue().isEmpty()) {
756 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
758 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
763 final OrderedLeafSetNode<?> readLeafList =
764 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
765 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
766 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
768 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
774 if (schemaNode instanceof ListSchemaNode) {
775 final OrderedMapNode readList =
776 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
777 if (readList == null || readList.getValue().isEmpty()) {
778 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
780 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
785 final OrderedLeafSetNode<?> readLeafList =
786 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
787 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
788 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
790 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
791 readLeafList, false);
796 throw new RestconfDocumentedException(
797 "Used bad value of insert parameter. Possible values are first, last, before or after, "
798 + "but was: " + insert);
802 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
803 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
804 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
805 final boolean before) {
806 rwTransaction.delete(datastore, path.getParent().getParent());
807 final InstanceIdentifierContext<?> instanceIdentifier =
808 ControllerContext.getInstance().toInstanceIdentifier(point);
809 int lastItemPosition = 0;
810 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
811 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
819 int lastInsertedPosition = 0;
820 final NormalizedNode<?, ?> emptySubtree =
821 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
822 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
823 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
824 if (lastInsertedPosition == lastItemPosition) {
825 checkItemDoesNotExists(rwTransaction, datastore, path);
826 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
828 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
829 checkItemDoesNotExists(rwTransaction, datastore, childPath);
830 rwTransaction.put(datastore, childPath, nodeChild);
831 lastInsertedPosition++;
835 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
836 final LogicalDatastoreType datastore,
837 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
838 final String point, final MapNode readList, final boolean before) {
839 rwTransaction.delete(datastore, path.getParent().getParent());
840 final InstanceIdentifierContext<?> instanceIdentifier =
841 ControllerContext.getInstance().toInstanceIdentifier(point);
842 int lastItemPosition = 0;
843 for (final MapEntryNode mapEntryNode : readList.getValue()) {
844 if (mapEntryNode.getIdentifier()
845 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
853 int lastInsertedPosition = 0;
854 final NormalizedNode<?, ?> emptySubtree =
855 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
856 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
857 for (final MapEntryNode mapEntryNode : readList.getValue()) {
858 if (lastInsertedPosition == lastItemPosition) {
859 checkItemDoesNotExists(rwTransaction, datastore, path);
860 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
862 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
863 checkItemDoesNotExists(rwTransaction, datastore, childPath);
864 rwTransaction.put(datastore, childPath, mapEntryNode);
865 lastInsertedPosition++;
869 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
870 final YangInstanceIdentifier parent = path.getParent();
871 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
872 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
874 if (dataSchemaNode instanceof ListSchemaNode) {
875 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
876 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
878 return dataSchemaNode;
880 if (dataSchemaNode instanceof LeafListSchemaNode) {
881 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
882 throw new RestconfDocumentedException(
883 "Insert parameter can be used only with ordered-by user leaf-list.");
885 return dataSchemaNode;
887 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
890 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
891 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
892 final SchemaContext schemaContext) {
893 final Collection<? extends NormalizedNode<?, ?>> children;
894 if (payload instanceof MapNode) {
895 children = ((MapNode) payload).getValue();
896 } else if (payload instanceof LeafSetNode) {
897 children = ((LeafSetNode<?>) payload).getValue();
899 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
903 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
904 if (children.isEmpty()) {
905 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
906 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
910 // Kick off batch existence check first...
911 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
913 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
914 // result of the existence checks...
915 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
916 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
917 for (final NormalizedNode<?, ?> child : children) {
918 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
919 // as that would allow us to skip the existence checks
920 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
923 // ... finally collect existence checks and abort the transaction if any of them failed.
924 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
926 failure = check.getFailure();
927 } catch (InterruptedException e) {
928 rwTransaction.cancel();
929 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
932 if (failure != null) {
933 rwTransaction.cancel();
934 final ReadFailedException e = failure.getValue();
936 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
937 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
940 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
945 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
946 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
947 final SchemaContext schemaContext) {
948 checkItemDoesNotExists(rwTransaction, datastore, path);
949 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
950 rwTransaction.put(datastore, path, payload);
953 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
954 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
956 return rwTransaction.exists(store, path).checkedGet();
957 } catch (ReadFailedException e) {
958 rwTransaction.cancel();
959 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
960 e, e.getErrorList());
965 * Check if item already exists. Throws error if it does NOT already exist.
966 * @param rwTransaction Current transaction
967 * @param store Used datastore
968 * @param path Path to item to verify its existence
970 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
971 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
972 if (!doesItemExist(rwTransaction, store, path)) {
973 final String errMsg = "Operation via Restconf was not executed because data does not exist";
974 LOG.trace("{}:{}", errMsg, path);
975 rwTransaction.cancel();
976 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
977 ErrorTag.DATA_MISSING);
982 * Check if item does NOT already exist. Throws error if it already exists.
983 * @param rwTransaction Current transaction
984 * @param store Used datastore
985 * @param path Path to item to verify its existence
987 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
988 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
989 if (doesItemExist(rwTransaction, store, path)) {
990 final String errMsg = "Operation via Restconf was not executed because data already exists";
991 LOG.trace("{}:{}", errMsg, path);
992 rwTransaction.cancel();
993 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
994 ErrorTag.DATA_EXISTS);
999 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1006 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1007 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1008 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1009 final String insert, final String point) {
1010 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1011 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1012 return readWriteTransaction.submit();
1016 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1018 private void putDataWithinTransaction(
1019 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1020 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1021 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1022 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1025 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1026 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1027 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1028 final String insert, final String point) {
1029 if (insert == null) {
1030 makePut(rwTransaction, datastore, path, payload, schemaContext);
1034 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1035 checkItemDoesNotExists(rwTransaction, datastore, path);
1038 if (schemaNode instanceof ListSchemaNode) {
1039 final OrderedMapNode readList =
1040 (OrderedMapNode) this.readConfigurationData(path.getParent());
1041 if (readList == null || readList.getValue().isEmpty()) {
1042 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1044 rwTransaction.delete(datastore, path.getParent());
1045 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1046 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1049 final OrderedLeafSetNode<?> readLeafList =
1050 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1051 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1052 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1054 rwTransaction.delete(datastore, path.getParent());
1055 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1056 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1062 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1065 if (schemaNode instanceof ListSchemaNode) {
1066 final OrderedMapNode readList =
1067 (OrderedMapNode) this.readConfigurationData(path.getParent());
1068 if (readList == null || readList.getValue().isEmpty()) {
1069 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1071 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1075 final OrderedLeafSetNode<?> readLeafList =
1076 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1077 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1078 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1080 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1081 readLeafList, true);
1086 if (schemaNode instanceof ListSchemaNode) {
1087 final OrderedMapNode readList =
1088 (OrderedMapNode) this.readConfigurationData(path.getParent());
1089 if (readList == null || readList.getValue().isEmpty()) {
1090 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1092 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1096 final OrderedLeafSetNode<?> readLeafList =
1097 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1098 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1099 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1101 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1102 readLeafList, false);
1107 throw new RestconfDocumentedException(
1108 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1113 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1114 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1115 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1116 final boolean before) {
1117 tx.delete(datastore, path.getParent());
1118 final InstanceIdentifierContext<?> instanceIdentifier =
1119 ControllerContext.getInstance().toInstanceIdentifier(point);
1121 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1122 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1131 final NormalizedNode<?, ?> emptySubtree =
1132 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1133 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1134 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1135 if (index2 == index1) {
1136 simplePut(datastore, path, tx, schemaContext, payload);
1138 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1139 tx.put(datastore, childPath, nodeChild);
1144 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1145 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1146 final String point, final OrderedMapNode readList, final boolean before) {
1147 tx.delete(datastore, path.getParent());
1148 final InstanceIdentifierContext<?> instanceIdentifier =
1149 ControllerContext.getInstance().toInstanceIdentifier(point);
1151 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1152 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1161 final NormalizedNode<?, ?> emptySubtree =
1162 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1163 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1164 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1165 if (index2 == index1) {
1166 simplePut(datastore, path, tx, schemaContext, payload);
1168 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1169 tx.put(datastore, childPath, mapEntryNode);
1174 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1175 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1176 if (payload instanceof MapNode) {
1177 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1178 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1179 ensureParentsByMerge(datastore, path, tx, schemaContext);
1180 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1181 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1182 tx.put(datastore, childPath, child);
1185 simplePut(datastore, path, tx, schemaContext, payload);
1189 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1190 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1191 ensureParentsByMerge(datastore, path, tx, schemaContext);
1192 tx.put(datastore, path, payload);
1195 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1196 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1197 final YangInstanceIdentifier path) {
1198 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1199 checkItemExists(readWriteTransaction, datastore, path);
1200 readWriteTransaction.delete(datastore, path);
1201 return readWriteTransaction.submit();
1204 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1205 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1206 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1207 tx.delete(datastore, path);
1210 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1211 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1212 final SchemaContext schemaContext) {
1213 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1214 ensureParentsByMerge(datastore, path, tx, schemaContext);
1216 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1217 // OpenDaylight should not change it.
1218 tx.merge(datastore, path, payload);
1221 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1222 this.domDataBroker = domDataBroker;
1225 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1226 checkPreconditions();
1228 if (listener.isListening()) {
1232 final SchemaPath path = listener.getSchemaPath();
1233 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1234 .registerNotificationListener(listener, path);
1236 listener.setRegistration(registration);
1239 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1240 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1241 final SchemaContext schemaContext) {
1242 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1243 YangInstanceIdentifier rootNormalizedPath = null;
1245 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1247 while (it.hasNext()) {
1248 final PathArgument pathArgument = it.next();
1249 if (rootNormalizedPath == null) {
1250 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1254 normalizedPathWithoutChildArgs.add(pathArgument);
1258 if (normalizedPathWithoutChildArgs.isEmpty()) {
1262 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1264 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1265 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1266 tx.merge(store, rootNormalizedPath, parentStructure);
1269 private static final class PatchStatusContextHelper {
1270 PatchStatusContext status;
1272 public PatchStatusContext getStatus() {
1276 public void setStatus(final PatchStatusContext status) {
1277 this.status = status;