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.controller.sal.core.api.Broker.ConsumerSession;
44 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
45 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
46 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
47 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
48 import org.opendaylight.yangtools.concepts.ListenerRegistration;
49 import org.opendaylight.yangtools.yang.common.QName;
50 import org.opendaylight.yangtools.yang.common.RpcError;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
55 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
57 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
65 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
66 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
67 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
68 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
69 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
70 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
71 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
72 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
78 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
82 public class BrokerFacade {
83 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
84 private static final BrokerFacade INSTANCE = new BrokerFacade();
86 private volatile DOMRpcService rpcService;
87 private volatile ConsumerSession context;
89 private DOMDataBroker domDataBroker;
90 private DOMNotificationService domNotification;
92 private BrokerFacade() {}
94 public void setRpcService(final DOMRpcService router) {
95 this.rpcService = router;
98 public void setDomNotificationService(final DOMNotificationService domNotification) {
99 this.domNotification = domNotification;
102 public void setContext(final ConsumerSession context) {
103 this.context = context;
106 public static BrokerFacade getInstance() {
107 return BrokerFacade.INSTANCE;
110 private void checkPreconditions() {
111 if (this.context == null || this.domDataBroker == null) {
112 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
117 * Read config data by path.
123 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
124 return readConfigurationData(path, null);
128 * Read config data by path.
133 * value of with-defaults parameter
136 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
137 checkPreconditions();
138 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
139 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
144 * Read config data from mount point by path.
147 * mount point for reading data
152 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
153 final YangInstanceIdentifier path) {
154 return readConfigurationData(mountPoint, path, null);
158 * Read config data from mount point by path.
161 * mount point for reading data
165 * value of with-defaults parameter
168 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
169 final String withDefa) {
170 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
171 if (domDataBrokerService.isPresent()) {
172 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
173 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
176 final String errMsg = "DOM data broker service isn't available for mount point " + path;
178 throw new RestconfDocumentedException(errMsg);
182 * Read operational data by path.
188 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
189 checkPreconditions();
191 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
192 return readDataViaTransaction(tx, OPERATIONAL, path);
197 * Read operational data from mount point by path.
200 * mount point for reading data
205 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
206 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
207 if (domDataBrokerService.isPresent()) {
208 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
209 return readDataViaTransaction(tx, OPERATIONAL, path);
212 final String errMsg = "DOM data broker service isn't available for mount point " + path;
214 throw new RestconfDocumentedException(errMsg);
218 * <b>PUT configuration data</b>
221 * Prepare result(status) for PUT operation and PUT data via transaction.
222 * Return wrapped status and future from PUT.
224 * @param globalSchema
225 * used by merge parents (if contains list)
234 * @return wrapper of status and future of PUT
236 public PutResult commitConfigurationDataPut(
237 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
238 final String insert, final String point) {
239 Preconditions.checkNotNull(globalSchema);
240 Preconditions.checkNotNull(path);
241 Preconditions.checkNotNull(payload);
243 checkPreconditions();
245 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
246 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
248 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
249 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
250 return new PutResult(status, future);
254 * <b>PUT configuration data (Mount point)</b>
257 * Prepare result(status) for PUT operation and PUT data via transaction.
258 * Return wrapped status and future from PUT.
261 * mount point for getting transaction for operation and schema
262 * context for merging parents(if contains list)
271 * @return wrapper of status and future of PUT
273 public PutResult commitMountPointDataPut(
274 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
275 final String insert, final String point) {
276 Preconditions.checkNotNull(mountPoint);
277 Preconditions.checkNotNull(path);
278 Preconditions.checkNotNull(payload);
280 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
281 if (domDataBrokerService.isPresent()) {
282 final DOMDataReadWriteTransaction newReadWriteTransaction =
283 domDataBrokerService.get().newReadWriteTransaction();
284 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
285 ? Status.OK : Status.CREATED;
286 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
287 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
289 return new PutResult(status, future);
291 final String errMsg = "DOM data broker service isn't available for mount point " + path;
293 throw new RestconfDocumentedException(errMsg);
296 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
298 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
300 // get new transaction and schema context on server or on mounted device
301 final SchemaContext schemaContext;
302 final DOMDataReadWriteTransaction patchTransaction;
303 if (mountPoint == null) {
304 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
305 patchTransaction = this.domDataBroker.newReadWriteTransaction();
307 schemaContext = mountPoint.getSchemaContext();
309 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
311 if (optional.isPresent()) {
312 patchTransaction = optional.get().newReadWriteTransaction();
314 // if mount point does not have broker it is not possible to continue and global error is reported
315 LOG.error("Http Patch {} has failed - device {} does not support broker service",
316 patchContext.getPatchId(), mountPoint.getIdentifier());
317 return new PatchStatusContext(
318 patchContext.getPatchId(),
321 ImmutableList.of(new RestconfError(
322 ErrorType.APPLICATION,
323 ErrorTag.OPERATION_FAILED,
324 "DOM data broker service isn't available for mount point "
325 + mountPoint.getIdentifier()))
330 final List<PatchStatusEntity> editCollection = new ArrayList<>();
331 List<RestconfError> editErrors;
332 boolean withoutError = true;
334 for (final PatchEntity patchEntity : patchContext.getData()) {
335 final PatchEditOperation operation = patchEntity.getOperation();
340 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
341 patchEntity.getNode(), schemaContext);
342 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
343 } catch (final RestconfDocumentedException e) {
344 LOG.error("Error call http Patch operation {} on target {}",
346 patchEntity.getTargetNode().toString());
348 editErrors = new ArrayList<>();
349 editErrors.addAll(e.getErrors());
350 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
351 withoutError = false;
358 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
359 .getTargetNode(), patchEntity.getNode(), schemaContext);
360 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
361 } catch (final RestconfDocumentedException e) {
362 LOG.error("Error call http Patch operation {} on target {}",
364 patchEntity.getTargetNode().toString());
366 editErrors = new ArrayList<>();
367 editErrors.addAll(e.getErrors());
368 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
369 withoutError = false;
376 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
378 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
379 } catch (final RestconfDocumentedException e) {
380 LOG.error("Error call http Patch operation {} on target {}",
382 patchEntity.getTargetNode().toString());
384 editErrors = new ArrayList<>();
385 editErrors.addAll(e.getErrors());
386 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
387 withoutError = false;
394 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
396 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
397 } catch (final RestconfDocumentedException e) {
398 LOG.error("Error call http Patch operation {} on target {}",
400 patchEntity.getTargetNode().toString());
402 editErrors = new ArrayList<>();
403 editErrors.addAll(e.getErrors());
404 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
405 withoutError = false;
412 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
413 patchEntity.getNode(), schemaContext);
414 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
415 } catch (final RestconfDocumentedException e) {
416 LOG.error("Error call http Patch operation {} on target {}",
418 patchEntity.getTargetNode().toString());
420 editErrors = new ArrayList<>();
421 editErrors.addAll(e.getErrors());
422 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
423 withoutError = false;
428 LOG.error("Unsupported http Patch operation {} on target {}",
430 patchEntity.getTargetNode().toString());
435 // if errors then cancel transaction and return error status
437 patchTransaction.cancel();
438 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
441 // if no errors commit transaction
442 final CountDownLatch waiter = new CountDownLatch(1);
443 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
444 final PatchStatusContextHelper status = new PatchStatusContextHelper();
446 Futures.addCallback(future, new FutureCallback<Void>() {
448 public void onSuccess(@Nullable final Void result) {
449 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
455 public void onFailure(final Throwable throwable) {
456 // if commit failed it is global error
457 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
458 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
459 false, ImmutableList.of(
460 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
466 return status.getStatus();
469 // POST configuration
470 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
471 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
472 final String insert, final String point) {
473 checkPreconditions();
474 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
475 globalSchema, insert, point);
478 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
479 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
480 final String insert, final String point) {
481 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
482 if (domDataBrokerService.isPresent()) {
483 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
484 payload, mountPoint.getSchemaContext(), insert, point);
486 final String errMsg = "DOM data broker service isn't available for mount point " + path;
488 throw new RestconfDocumentedException(errMsg);
491 // DELETE configuration
492 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
493 final YangInstanceIdentifier path) {
494 checkPreconditions();
495 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
498 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
499 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
500 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
501 if (domDataBrokerService.isPresent()) {
502 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
504 final String errMsg = "DOM data broker service isn't available for mount point " + path;
506 throw new RestconfDocumentedException(errMsg);
510 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
511 final NormalizedNode<?, ?> input) {
512 checkPreconditions();
513 if (this.rpcService == null) {
514 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
516 LOG.trace("Invoke RPC {} with input: {}", type, input);
517 return this.rpcService.invokeRpc(type, input);
520 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
521 final ListenerAdapter listener) {
522 checkPreconditions();
524 if (listener.isListening()) {
528 final YangInstanceIdentifier path = listener.getPath();
529 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
530 datastore, path, listener, scope);
532 listener.setRegistration(registration);
535 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
536 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
537 return readDataViaTransaction(transaction, datastore, path, null);
540 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
541 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
542 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
545 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
546 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
547 prepareDataByParamWithDef(optional.get(), path, withDefa);
548 } catch (ReadFailedException e) {
549 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
550 for (final RpcError error : e.getErrorList()) {
551 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
552 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
553 throw new RestconfDocumentedException(
556 ErrorTag.RESOURCE_DENIED_TRANSPORT);
559 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
563 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
564 final YangInstanceIdentifier path, final String withDefa) {
574 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
577 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
578 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
579 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
580 if (result instanceof ContainerNode) {
581 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
582 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
583 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
584 return builder.build();
587 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
588 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
589 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
590 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
591 return builder.build();
594 private void buildMapEntryBuilder(
595 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
596 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
597 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
598 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
599 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
600 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
601 if (child instanceof ContainerNode) {
602 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
603 Builders.containerBuilder((ContainerSchemaNode) childSchema);
604 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
605 builder.withChild(childBuilder.build());
606 } else if (child instanceof MapNode) {
607 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
608 Builders.mapBuilder((ListSchemaNode) childSchema);
609 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
610 ((ListSchemaNode) childSchema).getKeyDefinition());
611 builder.withChild(childBuilder.build());
612 } else if (child instanceof LeafNode) {
613 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
614 final String nodeVal = ((LeafNode<String>) child).getValue();
615 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
616 Builders.leafBuilder((LeafSchemaNode) childSchema);
617 if (keys.contains(child.getNodeType())) {
618 leafBuilder.withValue(((LeafNode<?>) child).getValue());
619 builder.withChild(leafBuilder.build());
622 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
623 leafBuilder.withValue(((LeafNode<?>) child).getValue());
624 builder.withChild(leafBuilder.build());
627 if (defaultVal != null && defaultVal.equals(nodeVal)) {
628 leafBuilder.withValue(((LeafNode<?>) child).getValue());
629 builder.withChild(leafBuilder.build());
637 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
638 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
639 final List<QName> keys) {
640 for (final MapEntryNode mapEntryNode : result.getValue()) {
641 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
642 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
643 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
644 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
645 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
646 builder.withChild(mapEntryBuilder.build());
650 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
651 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
652 final YangInstanceIdentifier actualPath, final boolean trim) {
653 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
654 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
655 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
656 if (child instanceof ContainerNode) {
657 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
658 Builders.containerBuilder((ContainerSchemaNode) childSchema);
659 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
660 builder.withChild(builderChild.build());
661 } else if (child instanceof MapNode) {
662 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
663 Builders.mapBuilder((ListSchemaNode) childSchema);
664 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
665 ((ListSchemaNode) childSchema).getKeyDefinition());
666 builder.withChild(childBuilder.build());
667 } else if (child instanceof LeafNode) {
668 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
669 final String nodeVal = ((LeafNode<String>) child).getValue();
670 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
671 Builders.leafBuilder((LeafSchemaNode) childSchema);
673 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
674 leafBuilder.withValue(((LeafNode<?>) child).getValue());
675 builder.withChild(leafBuilder.build());
678 if (defaultVal != null && defaultVal.equals(nodeVal)) {
679 leafBuilder.withValue(((LeafNode<?>) child).getValue());
680 builder.withChild(leafBuilder.build());
688 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
690 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
691 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
692 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
693 final String insert, final String point) {
694 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
695 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
696 return rwTransaction.submit();
700 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
702 private void postDataWithinTransaction(
703 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
704 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
705 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
706 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
709 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
710 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
711 final SchemaContext schemaContext, final String insert, final String point) {
712 if (insert == null) {
713 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
717 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
718 checkItemDoesNotExists(rwTransaction, datastore, path);
721 if (schemaNode instanceof ListSchemaNode) {
722 final OrderedMapNode readList =
723 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
724 if (readList == null || readList.getValue().isEmpty()) {
725 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
727 rwTransaction.delete(datastore, path.getParent().getParent());
728 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
729 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
733 final OrderedLeafSetNode<?> readLeafList =
734 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
735 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
736 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
738 rwTransaction.delete(datastore, path.getParent());
739 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
740 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
746 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
749 if (schemaNode instanceof ListSchemaNode) {
750 final OrderedMapNode readList =
751 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
752 if (readList == null || readList.getValue().isEmpty()) {
753 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
755 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
760 final OrderedLeafSetNode<?> readLeafList =
761 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
762 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
763 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
765 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
771 if (schemaNode instanceof ListSchemaNode) {
772 final OrderedMapNode readList =
773 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
774 if (readList == null || readList.getValue().isEmpty()) {
775 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
777 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
782 final OrderedLeafSetNode<?> readLeafList =
783 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
784 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
785 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
787 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
788 readLeafList, false);
793 throw new RestconfDocumentedException(
794 "Used bad value of insert parameter. Possible values are first, last, before or after, "
795 + "but was: " + insert);
799 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
800 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
801 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
802 final boolean before) {
803 rwTransaction.delete(datastore, path.getParent().getParent());
804 final InstanceIdentifierContext<?> instanceIdentifier =
805 ControllerContext.getInstance().toInstanceIdentifier(point);
806 int lastItemPosition = 0;
807 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
808 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
816 int lastInsertedPosition = 0;
817 final NormalizedNode<?, ?> emptySubtree =
818 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
819 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
820 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
821 if (lastInsertedPosition == lastItemPosition) {
822 checkItemDoesNotExists(rwTransaction, datastore, path);
823 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
825 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
826 checkItemDoesNotExists(rwTransaction, datastore, childPath);
827 rwTransaction.put(datastore, childPath, nodeChild);
828 lastInsertedPosition++;
832 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
833 final LogicalDatastoreType datastore,
834 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
835 final String point, final MapNode readList, final boolean before) {
836 rwTransaction.delete(datastore, path.getParent().getParent());
837 final InstanceIdentifierContext<?> instanceIdentifier =
838 ControllerContext.getInstance().toInstanceIdentifier(point);
839 int lastItemPosition = 0;
840 for (final MapEntryNode mapEntryNode : readList.getValue()) {
841 if (mapEntryNode.getIdentifier()
842 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
850 int lastInsertedPosition = 0;
851 final NormalizedNode<?, ?> emptySubtree =
852 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
853 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
854 for (final MapEntryNode mapEntryNode : readList.getValue()) {
855 if (lastInsertedPosition == lastItemPosition) {
856 checkItemDoesNotExists(rwTransaction, datastore, path);
857 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
859 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
860 checkItemDoesNotExists(rwTransaction, datastore, childPath);
861 rwTransaction.put(datastore, childPath, mapEntryNode);
862 lastInsertedPosition++;
866 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
867 final YangInstanceIdentifier parent = path.getParent();
868 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
869 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
871 if (dataSchemaNode instanceof ListSchemaNode) {
872 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
873 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
875 return dataSchemaNode;
877 if (dataSchemaNode instanceof LeafListSchemaNode) {
878 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
879 throw new RestconfDocumentedException(
880 "Insert parameter can be used only with ordered-by user leaf-list.");
882 return dataSchemaNode;
884 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
887 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
888 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
889 final SchemaContext schemaContext) {
890 final Collection<? extends NormalizedNode<?, ?>> children;
891 if (payload instanceof MapNode) {
892 children = ((MapNode) payload).getValue();
893 } else if (payload instanceof LeafSetNode) {
894 children = ((LeafSetNode<?>) payload).getValue();
896 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
900 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
901 if (children.isEmpty()) {
902 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
903 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
907 // Kick off batch existence check first...
908 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
910 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
911 // result of the existence checks...
912 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
913 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
914 for (final NormalizedNode<?, ?> child : children) {
915 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
916 // as that would allow us to skip the existence checks
917 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
920 // ... finally collect existence checks and abort the transaction if any of them failed.
921 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
923 failure = check.getFailure();
924 } catch (InterruptedException e) {
925 rwTransaction.cancel();
926 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
929 if (failure != null) {
930 rwTransaction.cancel();
931 final ReadFailedException e = failure.getValue();
933 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
934 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
937 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
942 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
943 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
944 final SchemaContext schemaContext) {
945 checkItemDoesNotExists(rwTransaction, datastore, path);
946 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
947 rwTransaction.put(datastore, path, payload);
950 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
951 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
953 return rwTransaction.exists(store, path).checkedGet();
954 } catch (ReadFailedException e) {
955 rwTransaction.cancel();
956 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
957 e, e.getErrorList());
962 * Check if item already exists. Throws error if it does NOT already exist.
963 * @param rwTransaction Current transaction
964 * @param store Used datastore
965 * @param path Path to item to verify its existence
967 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
968 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
969 if (!doesItemExist(rwTransaction, store, path)) {
970 final String errMsg = "Operation via Restconf was not executed because data does not exist";
971 LOG.trace("{}:{}", errMsg, path);
972 rwTransaction.cancel();
973 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
974 ErrorTag.DATA_MISSING);
979 * Check if item does NOT already exist. Throws error if it already exists.
980 * @param rwTransaction Current transaction
981 * @param store Used datastore
982 * @param path Path to item to verify its existence
984 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
985 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
986 if (doesItemExist(rwTransaction, store, path)) {
987 final String errMsg = "Operation via Restconf was not executed because data already exists";
988 LOG.trace("{}:{}", errMsg, path);
989 rwTransaction.cancel();
990 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
991 ErrorTag.DATA_EXISTS);
996 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1003 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1004 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1005 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1006 final String insert, final String point) {
1007 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1008 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1009 return readWriteTransaction.submit();
1013 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1015 private void putDataWithinTransaction(
1016 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1017 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1018 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1019 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1022 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1023 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1024 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1025 final String insert, final String point) {
1026 if (insert == null) {
1027 makePut(rwTransaction, datastore, path, payload, schemaContext);
1031 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1032 checkItemDoesNotExists(rwTransaction, datastore, path);
1035 if (schemaNode instanceof ListSchemaNode) {
1036 final OrderedMapNode readList =
1037 (OrderedMapNode) this.readConfigurationData(path.getParent());
1038 if (readList == null || readList.getValue().isEmpty()) {
1039 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1041 rwTransaction.delete(datastore, path.getParent());
1042 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1043 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1046 final OrderedLeafSetNode<?> readLeafList =
1047 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1048 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1049 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1051 rwTransaction.delete(datastore, path.getParent());
1052 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1053 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1059 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1062 if (schemaNode instanceof ListSchemaNode) {
1063 final OrderedMapNode readList =
1064 (OrderedMapNode) this.readConfigurationData(path.getParent());
1065 if (readList == null || readList.getValue().isEmpty()) {
1066 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1068 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1072 final OrderedLeafSetNode<?> readLeafList =
1073 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1074 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1075 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1077 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1078 readLeafList, true);
1083 if (schemaNode instanceof ListSchemaNode) {
1084 final OrderedMapNode readList =
1085 (OrderedMapNode) this.readConfigurationData(path.getParent());
1086 if (readList == null || readList.getValue().isEmpty()) {
1087 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1089 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1093 final OrderedLeafSetNode<?> readLeafList =
1094 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1095 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1096 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1098 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1099 readLeafList, false);
1104 throw new RestconfDocumentedException(
1105 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1110 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1111 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1112 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1113 final boolean before) {
1114 tx.delete(datastore, path.getParent());
1115 final InstanceIdentifierContext<?> instanceIdentifier =
1116 ControllerContext.getInstance().toInstanceIdentifier(point);
1118 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1119 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1128 final NormalizedNode<?, ?> emptySubtree =
1129 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1130 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1131 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1132 if (index2 == index1) {
1133 simplePut(datastore, path, tx, schemaContext, payload);
1135 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1136 tx.put(datastore, childPath, nodeChild);
1141 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1142 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1143 final String point, final OrderedMapNode readList, final boolean before) {
1144 tx.delete(datastore, path.getParent());
1145 final InstanceIdentifierContext<?> instanceIdentifier =
1146 ControllerContext.getInstance().toInstanceIdentifier(point);
1148 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1149 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1158 final NormalizedNode<?, ?> emptySubtree =
1159 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1160 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1161 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1162 if (index2 == index1) {
1163 simplePut(datastore, path, tx, schemaContext, payload);
1165 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1166 tx.put(datastore, childPath, mapEntryNode);
1171 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1172 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1173 if (payload instanceof MapNode) {
1174 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1175 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1176 ensureParentsByMerge(datastore, path, tx, schemaContext);
1177 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1178 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1179 tx.put(datastore, childPath, child);
1182 simplePut(datastore, path, tx, schemaContext, payload);
1186 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1187 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1188 ensureParentsByMerge(datastore, path, tx, schemaContext);
1189 tx.put(datastore, path, payload);
1192 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1193 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1194 final YangInstanceIdentifier path) {
1195 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1196 checkItemExists(readWriteTransaction, datastore, path);
1197 readWriteTransaction.delete(datastore, path);
1198 return readWriteTransaction.submit();
1201 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1202 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1203 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1204 tx.delete(datastore, path);
1207 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1208 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1209 final SchemaContext schemaContext) {
1210 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1211 ensureParentsByMerge(datastore, path, tx, schemaContext);
1213 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1214 // OpenDaylight should not change it.
1215 tx.merge(datastore, path, payload);
1218 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1219 this.domDataBroker = domDataBroker;
1222 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1223 checkPreconditions();
1225 if (listener.isListening()) {
1229 final SchemaPath path = listener.getSchemaPath();
1230 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1231 .registerNotificationListener(listener, path);
1233 listener.setRegistration(registration);
1236 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1237 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1238 final SchemaContext schemaContext) {
1239 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1240 YangInstanceIdentifier rootNormalizedPath = null;
1242 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1244 while (it.hasNext()) {
1245 final PathArgument pathArgument = it.next();
1246 if (rootNormalizedPath == null) {
1247 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1251 normalizedPathWithoutChildArgs.add(pathArgument);
1255 if (normalizedPathWithoutChildArgs.isEmpty()) {
1259 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1261 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1262 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1263 tx.merge(store, rootNormalizedPath, parentStructure);
1266 private static final class PatchStatusContextHelper {
1267 PatchStatusContext status;
1269 public PatchStatusContext getStatus() {
1273 public void setStatus(final PatchStatusContext status) {
1274 this.status = status;