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.DOMDataReadOnlyTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
38 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
39 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
40 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
43 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
44 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
45 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
46 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
47 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
48 import org.opendaylight.restconf.common.errors.RestconfError;
49 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
50 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
51 import org.opendaylight.restconf.common.patch.PatchContext;
52 import org.opendaylight.restconf.common.patch.PatchEditOperation;
53 import org.opendaylight.restconf.common.patch.PatchEntity;
54 import org.opendaylight.restconf.common.patch.PatchStatusContext;
55 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
56 import org.opendaylight.yangtools.concepts.ListenerRegistration;
57 import org.opendaylight.yangtools.yang.common.QName;
58 import org.opendaylight.yangtools.yang.common.RpcError;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
63 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
65 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
68 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
69 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
70 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
73 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
74 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
75 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
76 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
78 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
79 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
80 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
81 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
82 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
85 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
86 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
87 import org.slf4j.Logger;
88 import org.slf4j.LoggerFactory;
90 public class BrokerFacade {
91 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
92 private static final BrokerFacade INSTANCE = new BrokerFacade();
94 private volatile DOMRpcService rpcService;
96 private DOMDataBroker domDataBroker;
97 private DOMNotificationService domNotification;
99 private BrokerFacade() {}
101 public void setRpcService(final DOMRpcService router) {
102 this.rpcService = router;
105 public void setDomNotificationService(final DOMNotificationService domNotification) {
106 this.domNotification = domNotification;
109 public static BrokerFacade getInstance() {
110 return BrokerFacade.INSTANCE;
113 private void checkPreconditions() {
114 if (this.domDataBroker == null) {
115 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
120 * Read config data by path.
126 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
127 return readConfigurationData(path, null);
131 * Read config data by path.
136 * value of with-defaults parameter
139 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
140 checkPreconditions();
141 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
142 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
147 * Read config data from mount point by path.
150 * mount point for reading data
155 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
156 final YangInstanceIdentifier path) {
157 return readConfigurationData(mountPoint, path, null);
161 * Read config data from mount point by path.
164 * mount point for reading data
168 * value of with-defaults parameter
171 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
172 final String withDefa) {
173 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
174 if (domDataBrokerService.isPresent()) {
175 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
176 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
179 final String errMsg = "DOM data broker service isn't available for mount point " + path;
181 throw new RestconfDocumentedException(errMsg);
185 * Read operational data by path.
191 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
192 checkPreconditions();
194 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
195 return readDataViaTransaction(tx, OPERATIONAL, path);
200 * Read operational data from mount point by path.
203 * mount point for reading data
208 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
209 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
210 if (domDataBrokerService.isPresent()) {
211 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
212 return readDataViaTransaction(tx, OPERATIONAL, path);
215 final String errMsg = "DOM data broker service isn't available for mount point " + path;
217 throw new RestconfDocumentedException(errMsg);
221 * <b>PUT configuration data</b>
224 * Prepare result(status) for PUT operation and PUT data via transaction.
225 * Return wrapped status and future from PUT.
227 * @param globalSchema
228 * used by merge parents (if contains list)
237 * @return wrapper of status and future of PUT
239 public PutResult commitConfigurationDataPut(
240 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
241 final String insert, final String point) {
242 Preconditions.checkNotNull(globalSchema);
243 Preconditions.checkNotNull(path);
244 Preconditions.checkNotNull(payload);
246 checkPreconditions();
248 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
249 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
251 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
252 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
253 return new PutResult(status, future);
257 * <b>PUT configuration data (Mount point)</b>
260 * Prepare result(status) for PUT operation and PUT data via transaction.
261 * Return wrapped status and future from PUT.
264 * mount point for getting transaction for operation and schema
265 * context for merging parents(if contains list)
274 * @return wrapper of status and future of PUT
276 public PutResult commitMountPointDataPut(
277 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
278 final String insert, final String point) {
279 Preconditions.checkNotNull(mountPoint);
280 Preconditions.checkNotNull(path);
281 Preconditions.checkNotNull(payload);
283 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
284 if (domDataBrokerService.isPresent()) {
285 final DOMDataReadWriteTransaction newReadWriteTransaction =
286 domDataBrokerService.get().newReadWriteTransaction();
287 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
288 ? Status.OK : Status.CREATED;
289 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
290 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
292 return new PutResult(status, future);
294 final String errMsg = "DOM data broker service isn't available for mount point " + path;
296 throw new RestconfDocumentedException(errMsg);
299 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
301 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
303 // get new transaction and schema context on server or on mounted device
304 final SchemaContext schemaContext;
305 final DOMDataReadWriteTransaction patchTransaction;
306 if (mountPoint == null) {
307 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
308 patchTransaction = this.domDataBroker.newReadWriteTransaction();
310 schemaContext = mountPoint.getSchemaContext();
312 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
314 if (optional.isPresent()) {
315 patchTransaction = optional.get().newReadWriteTransaction();
317 // if mount point does not have broker it is not possible to continue and global error is reported
318 LOG.error("Http Patch {} has failed - device {} does not support broker service",
319 patchContext.getPatchId(), mountPoint.getIdentifier());
320 return new PatchStatusContext(
321 patchContext.getPatchId(),
324 ImmutableList.of(new RestconfError(
325 ErrorType.APPLICATION,
326 ErrorTag.OPERATION_FAILED,
327 "DOM data broker service isn't available for mount point "
328 + mountPoint.getIdentifier()))
333 final List<PatchStatusEntity> editCollection = new ArrayList<>();
334 List<RestconfError> editErrors;
335 boolean withoutError = true;
337 for (final PatchEntity patchEntity : patchContext.getData()) {
338 final PatchEditOperation operation = patchEntity.getOperation();
343 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
344 patchEntity.getNode(), schemaContext);
345 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
346 } catch (final RestconfDocumentedException e) {
347 LOG.error("Error call http Patch operation {} on target {}",
349 patchEntity.getTargetNode().toString());
351 editErrors = new ArrayList<>();
352 editErrors.addAll(e.getErrors());
353 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
354 withoutError = false;
361 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
362 .getTargetNode(), patchEntity.getNode(), schemaContext);
363 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
364 } catch (final RestconfDocumentedException e) {
365 LOG.error("Error call http Patch operation {} on target {}",
367 patchEntity.getTargetNode().toString());
369 editErrors = new ArrayList<>();
370 editErrors.addAll(e.getErrors());
371 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
372 withoutError = false;
379 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
381 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
382 } catch (final RestconfDocumentedException e) {
383 LOG.error("Error call http Patch operation {} on target {}",
385 patchEntity.getTargetNode().toString());
387 editErrors = new ArrayList<>();
388 editErrors.addAll(e.getErrors());
389 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
390 withoutError = false;
397 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
399 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
400 } catch (final RestconfDocumentedException e) {
401 LOG.error("Error call http Patch operation {} on target {}",
403 patchEntity.getTargetNode().toString());
405 editErrors = new ArrayList<>();
406 editErrors.addAll(e.getErrors());
407 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
408 withoutError = false;
415 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
416 patchEntity.getNode(), schemaContext);
417 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
418 } catch (final RestconfDocumentedException e) {
419 LOG.error("Error call http Patch operation {} on target {}",
421 patchEntity.getTargetNode().toString());
423 editErrors = new ArrayList<>();
424 editErrors.addAll(e.getErrors());
425 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
426 withoutError = false;
431 LOG.error("Unsupported http Patch operation {} on target {}",
433 patchEntity.getTargetNode().toString());
438 // if errors then cancel transaction and return error status
440 patchTransaction.cancel();
441 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
444 // if no errors commit transaction
445 final CountDownLatch waiter = new CountDownLatch(1);
446 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
447 final PatchStatusContextHelper status = new PatchStatusContextHelper();
449 Futures.addCallback(future, new FutureCallback<Void>() {
451 public void onSuccess(@Nullable final Void result) {
452 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
458 public void onFailure(final Throwable throwable) {
459 // if commit failed it is global error
460 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
461 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
462 false, ImmutableList.of(
463 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
469 return status.getStatus();
472 // POST configuration
473 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
474 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
475 final String insert, final String point) {
476 checkPreconditions();
477 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
478 globalSchema, insert, point);
481 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
482 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
483 final String insert, final String point) {
484 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
485 if (domDataBrokerService.isPresent()) {
486 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
487 payload, mountPoint.getSchemaContext(), insert, point);
489 final String errMsg = "DOM data broker service isn't available for mount point " + path;
491 throw new RestconfDocumentedException(errMsg);
494 // DELETE configuration
495 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
496 final YangInstanceIdentifier path) {
497 checkPreconditions();
498 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
501 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
502 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
503 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
504 if (domDataBrokerService.isPresent()) {
505 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
507 final String errMsg = "DOM data broker service isn't available for mount point " + path;
509 throw new RestconfDocumentedException(errMsg);
513 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
514 final NormalizedNode<?, ?> input) {
515 checkPreconditions();
516 if (this.rpcService == null) {
517 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
519 LOG.trace("Invoke RPC {} with input: {}", type, input);
520 return this.rpcService.invokeRpc(type, input);
523 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
524 final ListenerAdapter listener) {
525 checkPreconditions();
527 if (listener.isListening()) {
531 final YangInstanceIdentifier path = listener.getPath();
532 DOMDataTreeChangeService changeService = (DOMDataTreeChangeService)
533 this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
534 if (changeService == null) {
535 throw new UnsupportedOperationException("DOMDataBroker does not support the DOMDataTreeChangeService"
536 + this.domDataBroker);
538 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(datastore, path);
539 ListenerRegistration<ListenerAdapter> registration =
540 changeService.registerDataTreeChangeListener(root, listener);
541 listener.setRegistration(registration);
544 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
545 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
546 return readDataViaTransaction(transaction, datastore, path, null);
549 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
550 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
551 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
554 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
555 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
556 prepareDataByParamWithDef(optional.get(), path, withDefa);
557 } catch (ReadFailedException e) {
558 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
559 for (final RpcError error : e.getErrorList()) {
560 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
561 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
562 throw new RestconfDocumentedException(
565 ErrorTag.RESOURCE_DENIED_TRANSPORT);
568 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
572 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
573 final YangInstanceIdentifier path, final String withDefa) {
583 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
586 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
587 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
588 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
589 if (result instanceof ContainerNode) {
590 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
591 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
592 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
593 return builder.build();
596 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
597 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
598 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
599 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
600 return builder.build();
603 private void buildMapEntryBuilder(
604 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
605 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
606 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
607 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
608 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
609 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
610 if (child instanceof ContainerNode) {
611 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
612 Builders.containerBuilder((ContainerSchemaNode) childSchema);
613 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
614 builder.withChild(childBuilder.build());
615 } else if (child instanceof MapNode) {
616 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
617 Builders.mapBuilder((ListSchemaNode) childSchema);
618 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
619 ((ListSchemaNode) childSchema).getKeyDefinition());
620 builder.withChild(childBuilder.build());
621 } else if (child instanceof LeafNode) {
622 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
623 final String nodeVal = ((LeafNode<String>) child).getValue();
624 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
625 Builders.leafBuilder((LeafSchemaNode) childSchema);
626 if (keys.contains(child.getNodeType())) {
627 leafBuilder.withValue(((LeafNode<?>) child).getValue());
628 builder.withChild(leafBuilder.build());
631 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
632 leafBuilder.withValue(((LeafNode<?>) child).getValue());
633 builder.withChild(leafBuilder.build());
636 if (defaultVal != null && defaultVal.equals(nodeVal)) {
637 leafBuilder.withValue(((LeafNode<?>) child).getValue());
638 builder.withChild(leafBuilder.build());
646 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
647 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
648 final List<QName> keys) {
649 for (final MapEntryNode mapEntryNode : result.getValue()) {
650 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
651 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
652 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
653 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
654 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
655 builder.withChild(mapEntryBuilder.build());
659 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
660 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
661 final YangInstanceIdentifier actualPath, final boolean trim) {
662 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
663 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
664 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
665 if (child instanceof ContainerNode) {
666 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
667 Builders.containerBuilder((ContainerSchemaNode) childSchema);
668 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
669 builder.withChild(builderChild.build());
670 } else if (child instanceof MapNode) {
671 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
672 Builders.mapBuilder((ListSchemaNode) childSchema);
673 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
674 ((ListSchemaNode) childSchema).getKeyDefinition());
675 builder.withChild(childBuilder.build());
676 } else if (child instanceof LeafNode) {
677 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
678 final String nodeVal = ((LeafNode<String>) child).getValue();
679 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
680 Builders.leafBuilder((LeafSchemaNode) childSchema);
682 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
683 leafBuilder.withValue(((LeafNode<?>) child).getValue());
684 builder.withChild(leafBuilder.build());
687 if (defaultVal != null && defaultVal.equals(nodeVal)) {
688 leafBuilder.withValue(((LeafNode<?>) child).getValue());
689 builder.withChild(leafBuilder.build());
697 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
699 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
700 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
701 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
702 final String insert, final String point) {
703 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
704 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
705 return rwTransaction.submit();
709 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
711 private void postDataWithinTransaction(
712 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
713 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
714 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
715 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
718 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
719 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
720 final SchemaContext schemaContext, final String insert, final String point) {
721 if (insert == null) {
722 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
726 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
727 checkItemDoesNotExists(rwTransaction, datastore, path);
730 if (schemaNode instanceof ListSchemaNode) {
731 final OrderedMapNode readList =
732 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
733 if (readList == null || readList.getValue().isEmpty()) {
734 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
736 rwTransaction.delete(datastore, path.getParent().getParent());
737 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
738 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
742 final OrderedLeafSetNode<?> readLeafList =
743 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
744 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
745 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
747 rwTransaction.delete(datastore, path.getParent());
748 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
749 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
755 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
758 if (schemaNode instanceof ListSchemaNode) {
759 final OrderedMapNode readList =
760 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
761 if (readList == null || readList.getValue().isEmpty()) {
762 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
764 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
769 final OrderedLeafSetNode<?> readLeafList =
770 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
771 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
772 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
774 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
780 if (schemaNode instanceof ListSchemaNode) {
781 final OrderedMapNode readList =
782 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
783 if (readList == null || readList.getValue().isEmpty()) {
784 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
786 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
791 final OrderedLeafSetNode<?> readLeafList =
792 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
793 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
794 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
796 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
797 readLeafList, false);
802 throw new RestconfDocumentedException(
803 "Used bad value of insert parameter. Possible values are first, last, before or after, "
804 + "but was: " + insert);
808 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
809 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
810 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
811 final boolean before) {
812 rwTransaction.delete(datastore, path.getParent().getParent());
813 final InstanceIdentifierContext<?> instanceIdentifier =
814 ControllerContext.getInstance().toInstanceIdentifier(point);
815 int lastItemPosition = 0;
816 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
817 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
825 int lastInsertedPosition = 0;
826 final NormalizedNode<?, ?> emptySubtree =
827 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
828 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
829 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
830 if (lastInsertedPosition == lastItemPosition) {
831 checkItemDoesNotExists(rwTransaction, datastore, path);
832 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
834 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
835 checkItemDoesNotExists(rwTransaction, datastore, childPath);
836 rwTransaction.put(datastore, childPath, nodeChild);
837 lastInsertedPosition++;
841 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
842 final LogicalDatastoreType datastore,
843 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
844 final String point, final MapNode readList, final boolean before) {
845 rwTransaction.delete(datastore, path.getParent().getParent());
846 final InstanceIdentifierContext<?> instanceIdentifier =
847 ControllerContext.getInstance().toInstanceIdentifier(point);
848 int lastItemPosition = 0;
849 for (final MapEntryNode mapEntryNode : readList.getValue()) {
850 if (mapEntryNode.getIdentifier()
851 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
859 int lastInsertedPosition = 0;
860 final NormalizedNode<?, ?> emptySubtree =
861 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
862 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
863 for (final MapEntryNode mapEntryNode : readList.getValue()) {
864 if (lastInsertedPosition == lastItemPosition) {
865 checkItemDoesNotExists(rwTransaction, datastore, path);
866 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
868 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
869 checkItemDoesNotExists(rwTransaction, datastore, childPath);
870 rwTransaction.put(datastore, childPath, mapEntryNode);
871 lastInsertedPosition++;
875 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
876 final YangInstanceIdentifier parent = path.getParent();
877 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
878 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
880 if (dataSchemaNode instanceof ListSchemaNode) {
881 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
882 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
884 return dataSchemaNode;
886 if (dataSchemaNode instanceof LeafListSchemaNode) {
887 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
888 throw new RestconfDocumentedException(
889 "Insert parameter can be used only with ordered-by user leaf-list.");
891 return dataSchemaNode;
893 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
896 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
897 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
898 final SchemaContext schemaContext) {
899 final Collection<? extends NormalizedNode<?, ?>> children;
900 if (payload instanceof MapNode) {
901 children = ((MapNode) payload).getValue();
902 } else if (payload instanceof LeafSetNode) {
903 children = ((LeafSetNode<?>) payload).getValue();
905 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
909 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
910 if (children.isEmpty()) {
911 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
912 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
916 // Kick off batch existence check first...
917 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
919 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
920 // result of the existence checks...
921 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
922 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
923 for (final NormalizedNode<?, ?> child : children) {
924 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
925 // as that would allow us to skip the existence checks
926 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
929 // ... finally collect existence checks and abort the transaction if any of them failed.
930 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
932 failure = check.getFailure();
933 } catch (InterruptedException e) {
934 rwTransaction.cancel();
935 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
938 if (failure != null) {
939 rwTransaction.cancel();
940 final ReadFailedException e = failure.getValue();
942 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
943 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
946 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
951 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
952 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
953 final SchemaContext schemaContext) {
954 checkItemDoesNotExists(rwTransaction, datastore, path);
955 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
956 rwTransaction.put(datastore, path, payload);
959 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
960 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
962 return rwTransaction.exists(store, path).checkedGet();
963 } catch (ReadFailedException e) {
964 rwTransaction.cancel();
965 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
966 e, e.getErrorList());
971 * Check if item already exists. Throws error if it does NOT already exist.
972 * @param rwTransaction Current transaction
973 * @param store Used datastore
974 * @param path Path to item to verify its existence
976 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
977 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
978 if (!doesItemExist(rwTransaction, store, path)) {
979 final String errMsg = "Operation via Restconf was not executed because data does not exist";
980 LOG.trace("{}:{}", errMsg, path);
981 rwTransaction.cancel();
982 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
983 ErrorTag.DATA_MISSING);
988 * Check if item does NOT already exist. Throws error if it already exists.
989 * @param rwTransaction Current transaction
990 * @param store Used datastore
991 * @param path Path to item to verify its existence
993 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
994 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
995 if (doesItemExist(rwTransaction, store, path)) {
996 final String errMsg = "Operation via Restconf was not executed because data already exists";
997 LOG.trace("{}:{}", errMsg, path);
998 rwTransaction.cancel();
999 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
1000 ErrorTag.DATA_EXISTS);
1005 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1012 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1013 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1014 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1015 final String insert, final String point) {
1016 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1017 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1018 return readWriteTransaction.submit();
1022 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1024 private void putDataWithinTransaction(
1025 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1026 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1027 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1028 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1031 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1032 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1033 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1034 final String insert, final String point) {
1035 if (insert == null) {
1036 makePut(rwTransaction, datastore, path, payload, schemaContext);
1040 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1041 checkItemDoesNotExists(rwTransaction, datastore, path);
1044 if (schemaNode instanceof ListSchemaNode) {
1045 final OrderedMapNode readList =
1046 (OrderedMapNode) this.readConfigurationData(path.getParent());
1047 if (readList == null || readList.getValue().isEmpty()) {
1048 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1050 rwTransaction.delete(datastore, path.getParent());
1051 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1052 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1055 final OrderedLeafSetNode<?> readLeafList =
1056 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1057 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1058 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1060 rwTransaction.delete(datastore, path.getParent());
1061 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1062 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1068 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1071 if (schemaNode instanceof ListSchemaNode) {
1072 final OrderedMapNode readList =
1073 (OrderedMapNode) this.readConfigurationData(path.getParent());
1074 if (readList == null || readList.getValue().isEmpty()) {
1075 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1077 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1081 final OrderedLeafSetNode<?> readLeafList =
1082 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1083 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1084 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1086 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1087 readLeafList, true);
1092 if (schemaNode instanceof ListSchemaNode) {
1093 final OrderedMapNode readList =
1094 (OrderedMapNode) this.readConfigurationData(path.getParent());
1095 if (readList == null || readList.getValue().isEmpty()) {
1096 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1098 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1102 final OrderedLeafSetNode<?> readLeafList =
1103 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1104 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1105 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1107 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1108 readLeafList, false);
1113 throw new RestconfDocumentedException(
1114 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1119 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1120 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1121 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1122 final boolean before) {
1123 tx.delete(datastore, path.getParent());
1124 final InstanceIdentifierContext<?> instanceIdentifier =
1125 ControllerContext.getInstance().toInstanceIdentifier(point);
1127 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1128 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1137 final NormalizedNode<?, ?> emptySubtree =
1138 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1139 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1140 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1141 if (index2 == index1) {
1142 simplePut(datastore, path, tx, schemaContext, payload);
1144 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1145 tx.put(datastore, childPath, nodeChild);
1150 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1151 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1152 final String point, final OrderedMapNode readList, final boolean before) {
1153 tx.delete(datastore, path.getParent());
1154 final InstanceIdentifierContext<?> instanceIdentifier =
1155 ControllerContext.getInstance().toInstanceIdentifier(point);
1157 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1158 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1167 final NormalizedNode<?, ?> emptySubtree =
1168 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1169 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1170 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1171 if (index2 == index1) {
1172 simplePut(datastore, path, tx, schemaContext, payload);
1174 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1175 tx.put(datastore, childPath, mapEntryNode);
1180 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1181 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1182 if (payload instanceof MapNode) {
1183 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1184 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1185 ensureParentsByMerge(datastore, path, tx, schemaContext);
1186 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1187 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1188 tx.put(datastore, childPath, child);
1191 simplePut(datastore, path, tx, schemaContext, payload);
1195 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1196 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1197 ensureParentsByMerge(datastore, path, tx, schemaContext);
1198 tx.put(datastore, path, payload);
1201 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1202 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1203 final YangInstanceIdentifier path) {
1204 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1205 checkItemExists(readWriteTransaction, datastore, path);
1206 readWriteTransaction.delete(datastore, path);
1207 return readWriteTransaction.submit();
1210 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1211 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1212 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1213 tx.delete(datastore, path);
1216 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1217 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1218 final SchemaContext schemaContext) {
1219 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1220 ensureParentsByMerge(datastore, path, tx, schemaContext);
1222 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1223 // OpenDaylight should not change it.
1224 tx.merge(datastore, path, payload);
1227 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1228 this.domDataBroker = domDataBroker;
1231 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1232 checkPreconditions();
1234 if (listener.isListening()) {
1238 final SchemaPath path = listener.getSchemaPath();
1239 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1240 .registerNotificationListener(listener, path);
1242 listener.setRegistration(registration);
1245 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1246 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1247 final SchemaContext schemaContext) {
1248 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1249 YangInstanceIdentifier rootNormalizedPath = null;
1251 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1253 while (it.hasNext()) {
1254 final PathArgument pathArgument = it.next();
1255 if (rootNormalizedPath == null) {
1256 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1260 normalizedPathWithoutChildArgs.add(pathArgument);
1264 if (normalizedPathWithoutChildArgs.isEmpty()) {
1268 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1270 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1271 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1272 tx.merge(store, rootNormalizedPath, parentStructure);
1275 private static final class PatchStatusContextHelper {
1276 PatchStatusContext status;
1278 public PatchStatusContext getStatus() {
1282 public void setStatus(final PatchStatusContext status) {
1283 this.status = status;