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.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.DOMDataTreeChangeService;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
39 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
40 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
41 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
43 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
44 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
45 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
46 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
47 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
48 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
49 import org.opendaylight.restconf.common.errors.RestconfError;
50 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
51 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
52 import org.opendaylight.restconf.common.patch.PatchContext;
53 import org.opendaylight.restconf.common.patch.PatchEditOperation;
54 import org.opendaylight.restconf.common.patch.PatchEntity;
55 import org.opendaylight.restconf.common.patch.PatchStatusContext;
56 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
57 import org.opendaylight.yangtools.concepts.ListenerRegistration;
58 import org.opendaylight.yangtools.yang.common.QName;
59 import org.opendaylight.yangtools.yang.common.RpcError;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
64 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
65 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
66 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
68 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
69 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
70 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
74 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
75 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
76 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
78 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
79 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
80 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
81 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
82 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
85 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
86 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
87 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
91 public class BrokerFacade {
92 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
93 private static final BrokerFacade INSTANCE = new BrokerFacade();
95 private volatile DOMRpcService rpcService;
97 private DOMDataBroker domDataBroker;
98 private DOMNotificationService domNotification;
104 public void setRpcService(final DOMRpcService router) {
105 this.rpcService = router;
108 public void setDomNotificationService(final DOMNotificationService service) {
109 this.domNotification = service;
112 public static BrokerFacade getInstance() {
113 return BrokerFacade.INSTANCE;
116 private void checkPreconditions() {
117 if (this.domDataBroker == null) {
118 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
123 * Read config data by path.
129 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
130 return readConfigurationData(path, null);
134 * Read config data by path.
139 * value of with-defaults parameter
142 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
143 checkPreconditions();
144 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
145 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
150 * Read config data from mount point by path.
153 * mount point for reading data
158 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
159 final YangInstanceIdentifier path) {
160 return readConfigurationData(mountPoint, path, null);
164 * Read config data from mount point by path.
167 * mount point for reading data
171 * value of with-defaults parameter
174 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
175 final String withDefa) {
176 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
177 if (domDataBrokerService.isPresent()) {
178 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
179 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
182 final String errMsg = "DOM data broker service isn't available for mount point " + path;
184 throw new RestconfDocumentedException(errMsg);
188 * Read operational data by path.
194 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
195 checkPreconditions();
197 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
198 return readDataViaTransaction(tx, OPERATIONAL, path);
203 * Read operational data from mount point by path.
206 * mount point for reading data
211 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
212 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
213 if (domDataBrokerService.isPresent()) {
214 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
215 return readDataViaTransaction(tx, OPERATIONAL, path);
218 final String errMsg = "DOM data broker service isn't available for mount point " + path;
220 throw new RestconfDocumentedException(errMsg);
224 * <b>PUT configuration data</b>
227 * Prepare result(status) for PUT operation and PUT data via transaction.
228 * Return wrapped status and future from PUT.
230 * @param globalSchema
231 * used by merge parents (if contains list)
240 * @return wrapper of status and future of PUT
242 public PutResult commitConfigurationDataPut(
243 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
244 final String insert, final String point) {
245 Preconditions.checkNotNull(globalSchema);
246 Preconditions.checkNotNull(path);
247 Preconditions.checkNotNull(payload);
249 checkPreconditions();
251 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
252 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
254 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
255 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
256 return new PutResult(status, future);
260 * <b>PUT configuration data (Mount point)</b>
263 * Prepare result(status) for PUT operation and PUT data via transaction.
264 * Return wrapped status and future from PUT.
267 * mount point for getting transaction for operation and schema
268 * context for merging parents(if contains list)
277 * @return wrapper of status and future of PUT
279 public PutResult commitMountPointDataPut(
280 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
281 final String insert, final String point) {
282 Preconditions.checkNotNull(mountPoint);
283 Preconditions.checkNotNull(path);
284 Preconditions.checkNotNull(payload);
286 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
287 if (domDataBrokerService.isPresent()) {
288 final DOMDataReadWriteTransaction newReadWriteTransaction =
289 domDataBrokerService.get().newReadWriteTransaction();
290 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
291 ? Status.OK : Status.CREATED;
292 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
293 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
295 return new PutResult(status, future);
297 final String errMsg = "DOM data broker service isn't available for mount point " + path;
299 throw new RestconfDocumentedException(errMsg);
302 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
304 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
306 // get new transaction and schema context on server or on mounted device
307 final SchemaContext schemaContext;
308 final DOMDataReadWriteTransaction patchTransaction;
309 if (mountPoint == null) {
310 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
311 patchTransaction = this.domDataBroker.newReadWriteTransaction();
313 schemaContext = mountPoint.getSchemaContext();
315 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
317 if (optional.isPresent()) {
318 patchTransaction = optional.get().newReadWriteTransaction();
320 // if mount point does not have broker it is not possible to continue and global error is reported
321 LOG.error("Http Patch {} has failed - device {} does not support broker service",
322 patchContext.getPatchId(), mountPoint.getIdentifier());
323 return new PatchStatusContext(
324 patchContext.getPatchId(),
327 ImmutableList.of(new RestconfError(
328 ErrorType.APPLICATION,
329 ErrorTag.OPERATION_FAILED,
330 "DOM data broker service isn't available for mount point "
331 + mountPoint.getIdentifier()))
336 final List<PatchStatusEntity> editCollection = new ArrayList<>();
337 List<RestconfError> editErrors;
338 boolean withoutError = true;
340 for (final PatchEntity patchEntity : patchContext.getData()) {
341 final PatchEditOperation operation = patchEntity.getOperation();
346 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
347 patchEntity.getNode(), schemaContext);
348 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
349 } catch (final RestconfDocumentedException e) {
350 LOG.error("Error call http Patch operation {} on target {}",
352 patchEntity.getTargetNode().toString());
354 editErrors = new ArrayList<>();
355 editErrors.addAll(e.getErrors());
356 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
357 withoutError = false;
364 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
365 .getTargetNode(), patchEntity.getNode(), schemaContext);
366 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
367 } catch (final RestconfDocumentedException e) {
368 LOG.error("Error call http Patch operation {} on target {}",
370 patchEntity.getTargetNode().toString());
372 editErrors = new ArrayList<>();
373 editErrors.addAll(e.getErrors());
374 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
375 withoutError = false;
382 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
384 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
385 } catch (final RestconfDocumentedException e) {
386 LOG.error("Error call http Patch operation {} on target {}",
388 patchEntity.getTargetNode().toString());
390 editErrors = new ArrayList<>();
391 editErrors.addAll(e.getErrors());
392 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
393 withoutError = false;
400 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
402 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
403 } catch (final RestconfDocumentedException e) {
404 LOG.error("Error call http Patch operation {} on target {}",
406 patchEntity.getTargetNode().toString());
408 editErrors = new ArrayList<>();
409 editErrors.addAll(e.getErrors());
410 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
411 withoutError = false;
418 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
419 patchEntity.getNode(), schemaContext);
420 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
421 } catch (final RestconfDocumentedException e) {
422 LOG.error("Error call http Patch operation {} on target {}",
424 patchEntity.getTargetNode().toString());
426 editErrors = new ArrayList<>();
427 editErrors.addAll(e.getErrors());
428 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
429 withoutError = false;
434 LOG.error("Unsupported http Patch operation {} on target {}",
436 patchEntity.getTargetNode().toString());
441 // if errors then cancel transaction and return error status
443 patchTransaction.cancel();
444 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
447 // if no errors commit transaction
448 final CountDownLatch waiter = new CountDownLatch(1);
449 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
450 final PatchStatusContextHelper status = new PatchStatusContextHelper();
452 Futures.addCallback(future, new FutureCallback<Void>() {
454 public void onSuccess(@Nullable final Void result) {
455 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
461 public void onFailure(final Throwable throwable) {
462 // if commit failed it is global error
463 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
464 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
465 false, ImmutableList.of(
466 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
469 }, MoreExecutors.directExecutor());
472 return status.getStatus();
475 // POST configuration
476 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
477 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
478 final String insert, final String point) {
479 checkPreconditions();
480 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
481 globalSchema, insert, point);
484 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
485 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
486 final String insert, final String point) {
487 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
488 if (domDataBrokerService.isPresent()) {
489 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
490 payload, mountPoint.getSchemaContext(), insert, point);
492 final String errMsg = "DOM data broker service isn't available for mount point " + path;
494 throw new RestconfDocumentedException(errMsg);
497 // DELETE configuration
498 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
499 final YangInstanceIdentifier path) {
500 checkPreconditions();
501 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
504 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
505 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
506 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
507 if (domDataBrokerService.isPresent()) {
508 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
510 final String errMsg = "DOM data broker service isn't available for mount point " + path;
512 throw new RestconfDocumentedException(errMsg);
516 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
517 final NormalizedNode<?, ?> input) {
518 checkPreconditions();
519 if (this.rpcService == null) {
520 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
522 LOG.trace("Invoke RPC {} with input: {}", type, input);
523 return this.rpcService.invokeRpc(type, input);
526 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
527 final ListenerAdapter listener) {
528 checkPreconditions();
530 if (listener.isListening()) {
534 final YangInstanceIdentifier path = listener.getPath();
535 DOMDataTreeChangeService changeService = (DOMDataTreeChangeService)
536 this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
537 if (changeService == null) {
538 throw new UnsupportedOperationException("DOMDataBroker does not support the DOMDataTreeChangeService"
539 + this.domDataBroker);
541 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(datastore, path);
542 ListenerRegistration<ListenerAdapter> registration =
543 changeService.registerDataTreeChangeListener(root, listener);
544 listener.setRegistration(registration);
547 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
548 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
549 return readDataViaTransaction(transaction, datastore, path, null);
552 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
553 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
554 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
557 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
558 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
559 prepareDataByParamWithDef(optional.get(), path, withDefa);
560 } catch (ReadFailedException e) {
561 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
562 for (final RpcError error : e.getErrorList()) {
563 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
564 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
565 throw new RestconfDocumentedException(
568 ErrorTag.RESOURCE_DENIED_TRANSPORT, e);
571 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
575 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
576 final YangInstanceIdentifier path, final String withDefa) {
586 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
589 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
590 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
591 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
592 if (result instanceof ContainerNode) {
593 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
594 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
595 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
596 return builder.build();
599 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
600 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
601 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
602 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
603 return builder.build();
606 private void buildMapEntryBuilder(
607 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
608 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
609 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
610 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
611 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
612 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
613 if (child instanceof ContainerNode) {
614 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
615 Builders.containerBuilder((ContainerSchemaNode) childSchema);
616 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
617 builder.withChild(childBuilder.build());
618 } else if (child instanceof MapNode) {
619 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
620 Builders.mapBuilder((ListSchemaNode) childSchema);
621 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
622 ((ListSchemaNode) childSchema).getKeyDefinition());
623 builder.withChild(childBuilder.build());
624 } else if (child instanceof LeafNode) {
625 final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
626 final Object nodeVal = ((LeafNode<?>) child).getValue();
627 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
628 Builders.leafBuilder((LeafSchemaNode) childSchema);
629 if (keys.contains(child.getNodeType())) {
630 leafBuilder.withValue(((LeafNode<?>) child).getValue());
631 builder.withChild(leafBuilder.build());
634 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
635 leafBuilder.withValue(((LeafNode<?>) child).getValue());
636 builder.withChild(leafBuilder.build());
639 if (defaultVal != null && defaultVal.equals(nodeVal)) {
640 leafBuilder.withValue(((LeafNode<?>) child).getValue());
641 builder.withChild(leafBuilder.build());
649 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
650 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
651 final List<QName> keys) {
652 for (final MapEntryNode mapEntryNode : result.getValue()) {
653 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
654 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
655 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
656 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
657 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
658 builder.withChild(mapEntryBuilder.build());
662 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
663 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
664 final YangInstanceIdentifier actualPath, final boolean trim) {
665 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
666 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
667 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
668 if (child instanceof ContainerNode) {
669 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
670 Builders.containerBuilder((ContainerSchemaNode) childSchema);
671 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
672 builder.withChild(builderChild.build());
673 } else if (child instanceof MapNode) {
674 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
675 Builders.mapBuilder((ListSchemaNode) childSchema);
676 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
677 ((ListSchemaNode) childSchema).getKeyDefinition());
678 builder.withChild(childBuilder.build());
679 } else if (child instanceof LeafNode) {
680 final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
681 final Object nodeVal = ((LeafNode<?>) child).getValue();
682 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
683 Builders.leafBuilder((LeafSchemaNode) childSchema);
685 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
686 leafBuilder.withValue(((LeafNode<?>) child).getValue());
687 builder.withChild(leafBuilder.build());
690 if (defaultVal != null && defaultVal.equals(nodeVal)) {
691 leafBuilder.withValue(((LeafNode<?>) child).getValue());
692 builder.withChild(leafBuilder.build());
700 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
702 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
703 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
704 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
705 final String insert, final String point) {
706 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
707 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
708 return rwTransaction.submit();
712 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
714 private void postDataWithinTransaction(
715 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
716 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
717 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
718 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
721 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
722 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
723 final SchemaContext schemaContext, final String insert, final String point) {
724 if (insert == null) {
725 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
729 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
730 checkItemDoesNotExists(rwTransaction, datastore, path);
733 if (schemaNode instanceof ListSchemaNode) {
734 final OrderedMapNode readList =
735 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
736 if (readList == null || readList.getValue().isEmpty()) {
737 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
739 rwTransaction.delete(datastore, path.getParent().getParent());
740 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
741 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
745 final OrderedLeafSetNode<?> readLeafList =
746 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
747 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
748 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
750 rwTransaction.delete(datastore, path.getParent());
751 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
752 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
758 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
761 if (schemaNode instanceof ListSchemaNode) {
762 final OrderedMapNode readList =
763 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
764 if (readList == null || readList.getValue().isEmpty()) {
765 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
767 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
772 final OrderedLeafSetNode<?> readLeafList =
773 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
774 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
775 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
777 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
783 if (schemaNode instanceof ListSchemaNode) {
784 final OrderedMapNode readList =
785 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
786 if (readList == null || readList.getValue().isEmpty()) {
787 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
789 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
794 final OrderedLeafSetNode<?> readLeafList =
795 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
796 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
797 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
799 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
800 readLeafList, false);
805 throw new RestconfDocumentedException(
806 "Used bad value of insert parameter. Possible values are first, last, before or after, "
807 + "but was: " + insert);
811 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
812 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
813 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
814 final boolean before) {
815 rwTransaction.delete(datastore, path.getParent().getParent());
816 final InstanceIdentifierContext<?> instanceIdentifier =
817 ControllerContext.getInstance().toInstanceIdentifier(point);
818 int lastItemPosition = 0;
819 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
820 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
828 int lastInsertedPosition = 0;
829 final NormalizedNode<?, ?> emptySubtree =
830 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
831 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
832 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
833 if (lastInsertedPosition == lastItemPosition) {
834 checkItemDoesNotExists(rwTransaction, datastore, path);
835 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
837 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
838 checkItemDoesNotExists(rwTransaction, datastore, childPath);
839 rwTransaction.put(datastore, childPath, nodeChild);
840 lastInsertedPosition++;
844 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
845 final LogicalDatastoreType datastore,
846 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
847 final String point, final MapNode readList, final boolean before) {
848 rwTransaction.delete(datastore, path.getParent().getParent());
849 final InstanceIdentifierContext<?> instanceIdentifier =
850 ControllerContext.getInstance().toInstanceIdentifier(point);
851 int lastItemPosition = 0;
852 for (final MapEntryNode mapEntryNode : readList.getValue()) {
853 if (mapEntryNode.getIdentifier()
854 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
862 int lastInsertedPosition = 0;
863 final NormalizedNode<?, ?> emptySubtree =
864 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
865 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
866 for (final MapEntryNode mapEntryNode : readList.getValue()) {
867 if (lastInsertedPosition == lastItemPosition) {
868 checkItemDoesNotExists(rwTransaction, datastore, path);
869 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
871 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
872 checkItemDoesNotExists(rwTransaction, datastore, childPath);
873 rwTransaction.put(datastore, childPath, mapEntryNode);
874 lastInsertedPosition++;
878 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
879 final YangInstanceIdentifier parent = path.getParent();
880 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
881 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
883 if (dataSchemaNode instanceof ListSchemaNode) {
884 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
885 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
887 return dataSchemaNode;
889 if (dataSchemaNode instanceof LeafListSchemaNode) {
890 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
891 throw new RestconfDocumentedException(
892 "Insert parameter can be used only with ordered-by user leaf-list.");
894 return dataSchemaNode;
896 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
899 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
900 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
901 final SchemaContext schemaContext) {
902 final Collection<? extends NormalizedNode<?, ?>> children;
903 if (payload instanceof MapNode) {
904 children = ((MapNode) payload).getValue();
905 } else if (payload instanceof LeafSetNode) {
906 children = ((LeafSetNode<?>) payload).getValue();
908 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
912 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
913 if (children.isEmpty()) {
914 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
915 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
919 // Kick off batch existence check first...
920 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
922 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
923 // result of the existence checks...
924 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
925 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
926 for (final NormalizedNode<?, ?> child : children) {
927 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
928 // as that would allow us to skip the existence checks
929 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
932 // ... finally collect existence checks and abort the transaction if any of them failed.
933 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
935 failure = check.getFailure();
936 } catch (InterruptedException e) {
937 rwTransaction.cancel();
938 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
941 if (failure != null) {
942 rwTransaction.cancel();
943 final ReadFailedException e = failure.getValue();
945 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
946 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
949 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
954 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
955 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
956 final SchemaContext schemaContext) {
957 checkItemDoesNotExists(rwTransaction, datastore, path);
958 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
959 rwTransaction.put(datastore, path, payload);
962 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
963 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
965 return rwTransaction.exists(store, path).checkedGet();
966 } catch (ReadFailedException e) {
967 rwTransaction.cancel();
968 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
969 e, e.getErrorList());
974 * Check if item already exists. Throws error if it does NOT already exist.
975 * @param rwTransaction Current transaction
976 * @param store Used datastore
977 * @param path Path to item to verify its existence
979 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
980 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
981 if (!doesItemExist(rwTransaction, store, path)) {
982 final String errMsg = "Operation via Restconf was not executed because data does not exist";
983 LOG.trace("{}:{}", errMsg, path);
984 rwTransaction.cancel();
985 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
986 ErrorTag.DATA_MISSING);
991 * Check if item does NOT already exist. Throws error if it already exists.
992 * @param rwTransaction Current transaction
993 * @param store Used datastore
994 * @param path Path to item to verify its existence
996 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
997 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
998 if (doesItemExist(rwTransaction, store, path)) {
999 final String errMsg = "Operation via Restconf was not executed because data already exists";
1000 LOG.trace("{}:{}", errMsg, path);
1001 rwTransaction.cancel();
1002 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
1003 ErrorTag.DATA_EXISTS);
1008 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1015 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1016 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1017 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1018 final String insert, final String point) {
1019 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1020 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1021 return readWriteTransaction.submit();
1025 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1027 private void putDataWithinTransaction(
1028 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1029 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1030 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1031 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1034 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1035 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1036 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1037 final String insert, final String point) {
1038 if (insert == null) {
1039 makePut(rwTransaction, datastore, path, payload, schemaContext);
1043 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1044 checkItemDoesNotExists(rwTransaction, datastore, path);
1047 if (schemaNode instanceof ListSchemaNode) {
1048 final OrderedMapNode readList =
1049 (OrderedMapNode) this.readConfigurationData(path.getParent());
1050 if (readList == null || readList.getValue().isEmpty()) {
1051 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1053 rwTransaction.delete(datastore, path.getParent());
1054 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1055 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1058 final OrderedLeafSetNode<?> readLeafList =
1059 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1060 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1061 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1063 rwTransaction.delete(datastore, path.getParent());
1064 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1065 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1071 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1074 if (schemaNode instanceof ListSchemaNode) {
1075 final OrderedMapNode readList =
1076 (OrderedMapNode) this.readConfigurationData(path.getParent());
1077 if (readList == null || readList.getValue().isEmpty()) {
1078 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1080 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1084 final OrderedLeafSetNode<?> readLeafList =
1085 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1086 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1087 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1089 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1090 readLeafList, true);
1095 if (schemaNode instanceof ListSchemaNode) {
1096 final OrderedMapNode readList =
1097 (OrderedMapNode) this.readConfigurationData(path.getParent());
1098 if (readList == null || readList.getValue().isEmpty()) {
1099 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1101 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1105 final OrderedLeafSetNode<?> readLeafList =
1106 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1107 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1108 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1110 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1111 readLeafList, false);
1116 throw new RestconfDocumentedException(
1117 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1122 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1123 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1124 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1125 final boolean before) {
1126 tx.delete(datastore, path.getParent());
1127 final InstanceIdentifierContext<?> instanceIdentifier =
1128 ControllerContext.getInstance().toInstanceIdentifier(point);
1130 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1131 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1140 final NormalizedNode<?, ?> emptySubtree =
1141 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1142 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1143 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1144 if (index2 == index1) {
1145 simplePut(datastore, path, tx, schemaContext, payload);
1147 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1148 tx.put(datastore, childPath, nodeChild);
1153 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1154 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1155 final String point, final OrderedMapNode readList, final boolean before) {
1156 tx.delete(datastore, path.getParent());
1157 final InstanceIdentifierContext<?> instanceIdentifier =
1158 ControllerContext.getInstance().toInstanceIdentifier(point);
1160 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1161 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1170 final NormalizedNode<?, ?> emptySubtree =
1171 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1172 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1173 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1174 if (index2 == index1) {
1175 simplePut(datastore, path, tx, schemaContext, payload);
1177 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1178 tx.put(datastore, childPath, mapEntryNode);
1183 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1184 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1185 if (payload instanceof MapNode) {
1186 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1187 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1188 ensureParentsByMerge(datastore, path, tx, schemaContext);
1189 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1190 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1191 tx.put(datastore, childPath, child);
1194 simplePut(datastore, path, tx, schemaContext, payload);
1198 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1199 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1200 ensureParentsByMerge(datastore, path, tx, schemaContext);
1201 tx.put(datastore, path, payload);
1204 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1205 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1206 final YangInstanceIdentifier path) {
1207 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1208 checkItemExists(readWriteTransaction, datastore, path);
1209 readWriteTransaction.delete(datastore, path);
1210 return readWriteTransaction.submit();
1213 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1214 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1215 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1216 tx.delete(datastore, path);
1219 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1220 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1221 final SchemaContext schemaContext) {
1222 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1223 ensureParentsByMerge(datastore, path, tx, schemaContext);
1225 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1226 // OpenDaylight should not change it.
1227 tx.merge(datastore, path, payload);
1230 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1231 this.domDataBroker = domDataBroker;
1234 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1235 checkPreconditions();
1237 if (listener.isListening()) {
1241 final SchemaPath path = listener.getSchemaPath();
1242 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1243 .registerNotificationListener(listener, path);
1245 listener.setRegistration(registration);
1248 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1249 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1250 final SchemaContext schemaContext) {
1251 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1252 YangInstanceIdentifier rootNormalizedPath = null;
1254 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1256 while (it.hasNext()) {
1257 final PathArgument pathArgument = it.next();
1258 if (rootNormalizedPath == null) {
1259 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1263 normalizedPathWithoutChildArgs.add(pathArgument);
1267 if (normalizedPathWithoutChildArgs.isEmpty()) {
1271 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1273 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1274 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1275 tx.merge(store, rootNormalizedPath, parentStructure);
1278 private static final class PatchStatusContextHelper {
1279 PatchStatusContext status;
1281 public PatchStatusContext getStatus() {
1285 public void setStatus(final PatchStatusContext status) {
1286 this.status = status;