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 = PatchEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
341 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
342 patchEntity.getNode(), schemaContext);
343 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
344 } catch (final RestconfDocumentedException e) {
345 LOG.error("Error call http Patch operation {} on target {}",
347 patchEntity.getTargetNode().toString());
349 editErrors = new ArrayList<>();
350 editErrors.addAll(e.getErrors());
351 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
352 withoutError = false;
359 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
360 .getTargetNode(), patchEntity.getNode(), schemaContext);
361 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
362 } catch (final RestconfDocumentedException e) {
363 LOG.error("Error call http Patch operation {} on target {}",
365 patchEntity.getTargetNode().toString());
367 editErrors = new ArrayList<>();
368 editErrors.addAll(e.getErrors());
369 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
370 withoutError = false;
377 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
379 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
380 } catch (final RestconfDocumentedException e) {
381 LOG.error("Error call http Patch operation {} on target {}",
383 patchEntity.getTargetNode().toString());
385 editErrors = new ArrayList<>();
386 editErrors.addAll(e.getErrors());
387 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
388 withoutError = false;
395 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
397 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
398 } catch (final RestconfDocumentedException e) {
399 LOG.error("Error call http Patch operation {} on target {}",
401 patchEntity.getTargetNode().toString());
403 editErrors = new ArrayList<>();
404 editErrors.addAll(e.getErrors());
405 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
406 withoutError = false;
413 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
414 patchEntity.getNode(), schemaContext);
415 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
416 } catch (final RestconfDocumentedException e) {
417 LOG.error("Error call http Patch operation {} on target {}",
419 patchEntity.getTargetNode().toString());
421 editErrors = new ArrayList<>();
422 editErrors.addAll(e.getErrors());
423 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
424 withoutError = false;
429 LOG.error("Unsupported http Patch operation {} on target {}",
431 patchEntity.getTargetNode().toString());
436 // if errors then cancel transaction and return error status
438 patchTransaction.cancel();
439 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
442 // if no errors commit transaction
443 final CountDownLatch waiter = new CountDownLatch(1);
444 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
445 final PatchStatusContextHelper status = new PatchStatusContextHelper();
447 Futures.addCallback(future, new FutureCallback<Void>() {
449 public void onSuccess(@Nullable final Void result) {
450 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
456 public void onFailure(final Throwable throwable) {
457 // if commit failed it is global error
458 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
459 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
460 false, ImmutableList.of(
461 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
467 return status.getStatus();
470 // POST configuration
471 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
472 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
473 final String insert, final String point) {
474 checkPreconditions();
475 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
476 globalSchema, insert, point);
479 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
480 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
481 final String insert, final String point) {
482 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
483 if (domDataBrokerService.isPresent()) {
484 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
485 payload, mountPoint.getSchemaContext(), insert, point);
487 final String errMsg = "DOM data broker service isn't available for mount point " + path;
489 throw new RestconfDocumentedException(errMsg);
492 // DELETE configuration
493 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
494 final YangInstanceIdentifier path) {
495 checkPreconditions();
496 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
499 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
500 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
501 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
502 if (domDataBrokerService.isPresent()) {
503 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
505 final String errMsg = "DOM data broker service isn't available for mount point " + path;
507 throw new RestconfDocumentedException(errMsg);
511 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
512 final NormalizedNode<?, ?> input) {
513 checkPreconditions();
514 if (this.rpcService == null) {
515 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
517 LOG.trace("Invoke RPC {} with input: {}", type, input);
518 return this.rpcService.invokeRpc(type, input);
521 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
522 final ListenerAdapter listener) {
523 checkPreconditions();
525 if (listener.isListening()) {
529 final YangInstanceIdentifier path = listener.getPath();
530 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
531 datastore, path, listener, scope);
533 listener.setRegistration(registration);
536 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
537 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
538 return readDataViaTransaction(transaction, datastore, path, null);
541 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
542 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
543 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
546 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
547 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
548 prepareDataByParamWithDef(optional.get(), path, withDefa);
549 } catch (ReadFailedException e) {
550 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
551 for (final RpcError error : e.getErrorList()) {
552 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
553 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
554 throw new RestconfDocumentedException(
557 ErrorTag.RESOURCE_DENIED_TRANSPORT);
560 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
564 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
565 final YangInstanceIdentifier path, final String withDefa) {
575 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
578 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
579 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
580 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
581 if (result instanceof ContainerNode) {
582 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
583 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
584 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
585 return builder.build();
588 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
589 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
590 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
591 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
592 return builder.build();
595 private void buildMapEntryBuilder(
596 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
597 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
598 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
599 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
600 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
601 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
602 if (child instanceof ContainerNode) {
603 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
604 Builders.containerBuilder((ContainerSchemaNode) childSchema);
605 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
606 builder.withChild(childBuilder.build());
607 } else if (child instanceof MapNode) {
608 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
609 Builders.mapBuilder((ListSchemaNode) childSchema);
610 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
611 ((ListSchemaNode) childSchema).getKeyDefinition());
612 builder.withChild(childBuilder.build());
613 } else if (child instanceof LeafNode) {
614 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
615 final String nodeVal = ((LeafNode<String>) child).getValue();
616 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
617 Builders.leafBuilder((LeafSchemaNode) childSchema);
618 if (keys.contains(child.getNodeType())) {
619 leafBuilder.withValue(((LeafNode<?>) child).getValue());
620 builder.withChild(leafBuilder.build());
623 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
624 leafBuilder.withValue(((LeafNode<?>) child).getValue());
625 builder.withChild(leafBuilder.build());
628 if (defaultVal != null && defaultVal.equals(nodeVal)) {
629 leafBuilder.withValue(((LeafNode<?>) child).getValue());
630 builder.withChild(leafBuilder.build());
638 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
639 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
640 final List<QName> keys) {
641 for (final MapEntryNode mapEntryNode : result.getValue()) {
642 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
643 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
644 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
645 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
646 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
647 builder.withChild(mapEntryBuilder.build());
651 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
652 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
653 final YangInstanceIdentifier actualPath, final boolean trim) {
654 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
655 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
656 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
657 if (child instanceof ContainerNode) {
658 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
659 Builders.containerBuilder((ContainerSchemaNode) childSchema);
660 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
661 builder.withChild(builderChild.build());
662 } else if (child instanceof MapNode) {
663 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
664 Builders.mapBuilder((ListSchemaNode) childSchema);
665 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
666 ((ListSchemaNode) childSchema).getKeyDefinition());
667 builder.withChild(childBuilder.build());
668 } else if (child instanceof LeafNode) {
669 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
670 final String nodeVal = ((LeafNode<String>) child).getValue();
671 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
672 Builders.leafBuilder((LeafSchemaNode) childSchema);
674 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
675 leafBuilder.withValue(((LeafNode<?>) child).getValue());
676 builder.withChild(leafBuilder.build());
679 if (defaultVal != null && defaultVal.equals(nodeVal)) {
680 leafBuilder.withValue(((LeafNode<?>) child).getValue());
681 builder.withChild(leafBuilder.build());
689 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
691 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
692 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
693 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
694 final String insert, final String point) {
695 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
696 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
697 return rwTransaction.submit();
701 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
703 private void postDataWithinTransaction(
704 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
705 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
706 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
707 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
710 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
711 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
712 final SchemaContext schemaContext, final String insert, final String point) {
713 if (insert == null) {
714 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
718 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
719 checkItemDoesNotExists(rwTransaction, datastore, path);
722 if (schemaNode instanceof ListSchemaNode) {
723 final OrderedMapNode readList =
724 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
725 if (readList == null || readList.getValue().isEmpty()) {
726 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
728 rwTransaction.delete(datastore, path.getParent().getParent());
729 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
730 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
734 final OrderedLeafSetNode<?> readLeafList =
735 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
736 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
737 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
739 rwTransaction.delete(datastore, path.getParent());
740 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
741 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
747 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
750 if (schemaNode instanceof ListSchemaNode) {
751 final OrderedMapNode readList =
752 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
753 if (readList == null || readList.getValue().isEmpty()) {
754 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
756 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
761 final OrderedLeafSetNode<?> readLeafList =
762 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
763 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
764 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
766 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
772 if (schemaNode instanceof ListSchemaNode) {
773 final OrderedMapNode readList =
774 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
775 if (readList == null || readList.getValue().isEmpty()) {
776 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
778 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
783 final OrderedLeafSetNode<?> readLeafList =
784 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
785 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
786 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
788 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
789 readLeafList, false);
794 throw new RestconfDocumentedException(
795 "Used bad value of insert parameter. Possible values are first, last, before or after, "
796 + "but was: " + insert);
800 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
801 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
802 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
803 final boolean before) {
804 rwTransaction.delete(datastore, path.getParent().getParent());
805 final InstanceIdentifierContext<?> instanceIdentifier =
806 ControllerContext.getInstance().toInstanceIdentifier(point);
807 int lastItemPosition = 0;
808 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
809 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
817 int lastInsertedPosition = 0;
818 final NormalizedNode<?, ?> emptySubtree =
819 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
820 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
821 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
822 if (lastInsertedPosition == lastItemPosition) {
823 checkItemDoesNotExists(rwTransaction, datastore, path);
824 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
826 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
827 checkItemDoesNotExists(rwTransaction, datastore, childPath);
828 rwTransaction.put(datastore, childPath, nodeChild);
829 lastInsertedPosition++;
833 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
834 final LogicalDatastoreType datastore,
835 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
836 final String point, final MapNode readList, final boolean before) {
837 rwTransaction.delete(datastore, path.getParent().getParent());
838 final InstanceIdentifierContext<?> instanceIdentifier =
839 ControllerContext.getInstance().toInstanceIdentifier(point);
840 int lastItemPosition = 0;
841 for (final MapEntryNode mapEntryNode : readList.getValue()) {
842 if (mapEntryNode.getIdentifier()
843 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
851 int lastInsertedPosition = 0;
852 final NormalizedNode<?, ?> emptySubtree =
853 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
854 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
855 for (final MapEntryNode mapEntryNode : readList.getValue()) {
856 if (lastInsertedPosition == lastItemPosition) {
857 checkItemDoesNotExists(rwTransaction, datastore, path);
858 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
860 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
861 checkItemDoesNotExists(rwTransaction, datastore, childPath);
862 rwTransaction.put(datastore, childPath, mapEntryNode);
863 lastInsertedPosition++;
867 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
868 final YangInstanceIdentifier parent = path.getParent();
869 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
870 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
872 if (dataSchemaNode instanceof ListSchemaNode) {
873 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
874 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
876 return dataSchemaNode;
878 if (dataSchemaNode instanceof LeafListSchemaNode) {
879 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
880 throw new RestconfDocumentedException(
881 "Insert parameter can be used only with ordered-by user leaf-list.");
883 return dataSchemaNode;
885 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
888 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
889 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
890 final SchemaContext schemaContext) {
891 final Collection<? extends NormalizedNode<?, ?>> children;
892 if (payload instanceof MapNode) {
893 children = ((MapNode) payload).getValue();
894 } else if (payload instanceof LeafSetNode) {
895 children = ((LeafSetNode<?>) payload).getValue();
897 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
901 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
902 if (children.isEmpty()) {
903 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
904 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
908 // Kick off batch existence check first...
909 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
911 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
912 // result of the existence checks...
913 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
914 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
915 for (final NormalizedNode<?, ?> child : children) {
916 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
917 // as that would allow us to skip the existence checks
918 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
921 // ... finally collect existence checks and abort the transaction if any of them failed.
922 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
924 failure = check.getFailure();
925 } catch (InterruptedException e) {
926 rwTransaction.cancel();
927 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
930 if (failure != null) {
931 rwTransaction.cancel();
932 final ReadFailedException e = failure.getValue();
934 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
935 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
938 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
943 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
944 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
945 final SchemaContext schemaContext) {
946 checkItemDoesNotExists(rwTransaction, datastore, path);
947 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
948 rwTransaction.put(datastore, path, payload);
951 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
952 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
954 return rwTransaction.exists(store, path).checkedGet();
955 } catch (ReadFailedException e) {
956 rwTransaction.cancel();
957 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
958 e, e.getErrorList());
963 * Check if item already exists. Throws error if it does NOT already exist.
964 * @param rwTransaction Current transaction
965 * @param store Used datastore
966 * @param path Path to item to verify its existence
968 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
969 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
970 if (!doesItemExist(rwTransaction, store, path)) {
971 final String errMsg = "Operation via Restconf was not executed because data does not exist";
972 LOG.trace("{}:{}", errMsg, path);
973 rwTransaction.cancel();
974 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
975 ErrorTag.DATA_MISSING);
980 * Check if item does NOT already exist. Throws error if it already exists.
981 * @param rwTransaction Current transaction
982 * @param store Used datastore
983 * @param path Path to item to verify its existence
985 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
986 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
987 if (doesItemExist(rwTransaction, store, path)) {
988 final String errMsg = "Operation via Restconf was not executed because data already exists";
989 LOG.trace("{}:{}", errMsg, path);
990 rwTransaction.cancel();
991 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
992 ErrorTag.DATA_EXISTS);
997 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1004 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1005 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1006 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1007 final String insert, final String point) {
1008 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1009 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1010 return readWriteTransaction.submit();
1014 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1016 private void putDataWithinTransaction(
1017 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1018 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1019 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1020 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1023 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1024 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1025 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1026 final String insert, final String point) {
1027 if (insert == null) {
1028 makePut(rwTransaction, datastore, path, payload, schemaContext);
1032 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1033 checkItemDoesNotExists(rwTransaction, datastore, path);
1036 if (schemaNode instanceof ListSchemaNode) {
1037 final OrderedMapNode readList =
1038 (OrderedMapNode) this.readConfigurationData(path.getParent());
1039 if (readList == null || readList.getValue().isEmpty()) {
1040 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1042 rwTransaction.delete(datastore, path.getParent());
1043 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1044 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1047 final OrderedLeafSetNode<?> readLeafList =
1048 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1049 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1050 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1052 rwTransaction.delete(datastore, path.getParent());
1053 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1054 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1060 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1063 if (schemaNode instanceof ListSchemaNode) {
1064 final OrderedMapNode readList =
1065 (OrderedMapNode) this.readConfigurationData(path.getParent());
1066 if (readList == null || readList.getValue().isEmpty()) {
1067 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1069 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1073 final OrderedLeafSetNode<?> readLeafList =
1074 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1075 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1076 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1078 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1079 readLeafList, true);
1084 if (schemaNode instanceof ListSchemaNode) {
1085 final OrderedMapNode readList =
1086 (OrderedMapNode) this.readConfigurationData(path.getParent());
1087 if (readList == null || readList.getValue().isEmpty()) {
1088 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1090 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1094 final OrderedLeafSetNode<?> readLeafList =
1095 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1096 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1097 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1099 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1100 readLeafList, false);
1105 throw new RestconfDocumentedException(
1106 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1111 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1112 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1113 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1114 final boolean before) {
1115 tx.delete(datastore, path.getParent());
1116 final InstanceIdentifierContext<?> instanceIdentifier =
1117 ControllerContext.getInstance().toInstanceIdentifier(point);
1119 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1120 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1129 final NormalizedNode<?, ?> emptySubtree =
1130 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1131 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1132 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1133 if (index2 == index1) {
1134 simplePut(datastore, path, tx, schemaContext, payload);
1136 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1137 tx.put(datastore, childPath, nodeChild);
1142 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1143 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1144 final String point, final OrderedMapNode readList, final boolean before) {
1145 tx.delete(datastore, path.getParent());
1146 final InstanceIdentifierContext<?> instanceIdentifier =
1147 ControllerContext.getInstance().toInstanceIdentifier(point);
1149 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1150 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1159 final NormalizedNode<?, ?> emptySubtree =
1160 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1161 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1162 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1163 if (index2 == index1) {
1164 simplePut(datastore, path, tx, schemaContext, payload);
1166 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1167 tx.put(datastore, childPath, mapEntryNode);
1172 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1173 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1174 if (payload instanceof MapNode) {
1175 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1176 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1177 ensureParentsByMerge(datastore, path, tx, schemaContext);
1178 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1179 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1180 tx.put(datastore, childPath, child);
1183 simplePut(datastore, path, tx, schemaContext, payload);
1187 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1188 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1189 ensureParentsByMerge(datastore, path, tx, schemaContext);
1190 tx.put(datastore, path, payload);
1193 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1194 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1195 final YangInstanceIdentifier path) {
1196 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1197 checkItemExists(readWriteTransaction, datastore, path);
1198 readWriteTransaction.delete(datastore, path);
1199 return readWriteTransaction.submit();
1202 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1203 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1204 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1205 tx.delete(datastore, path);
1208 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1209 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1210 final SchemaContext schemaContext) {
1211 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1212 ensureParentsByMerge(datastore, path, tx, schemaContext);
1214 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1215 // OpenDaylight should not change it.
1216 tx.merge(datastore, path, payload);
1219 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1220 this.domDataBroker = domDataBroker;
1223 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1224 checkPreconditions();
1226 if (listener.isListening()) {
1230 final SchemaPath path = listener.getSchemaPath();
1231 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1232 .registerNotificationListener(listener, path);
1234 listener.setRegistration(registration);
1237 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1238 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1239 final SchemaContext schemaContext) {
1240 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1241 YangInstanceIdentifier rootNormalizedPath = null;
1243 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1245 while (it.hasNext()) {
1246 final PathArgument pathArgument = it.next();
1247 if (rootNormalizedPath == null) {
1248 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1252 normalizedPathWithoutChildArgs.add(pathArgument);
1256 if (normalizedPathWithoutChildArgs.isEmpty()) {
1260 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1262 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1263 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1264 tx.merge(store, rootNormalizedPath, parentStructure);
1267 private static final class PatchStatusContextHelper {
1268 PatchStatusContext status;
1270 public PatchStatusContext getStatus() {
1274 public void setStatus(final PatchStatusContext status) {
1275 this.status = status;