2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.sal.restconf.impl;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.io.Closeable;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map.Entry;
26 import java.util.concurrent.CountDownLatch;
27 import javax.annotation.Nullable;
28 import javax.ws.rs.core.Response.Status;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
40 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
41 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
42 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
43 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
44 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
45 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
46 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
47 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
48 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
49 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
50 import org.opendaylight.restconf.common.errors.RestconfError;
51 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
52 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
53 import org.opendaylight.restconf.common.patch.PatchContext;
54 import org.opendaylight.restconf.common.patch.PatchEditOperation;
55 import org.opendaylight.restconf.common.patch.PatchEntity;
56 import org.opendaylight.restconf.common.patch.PatchStatusContext;
57 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
58 import org.opendaylight.yangtools.concepts.ListenerRegistration;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.common.RpcError;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
65 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
67 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
68 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
69 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
70 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
75 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
76 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
78 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
79 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
80 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
81 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
82 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
85 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
86 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
87 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
88 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
92 @SuppressWarnings("checkstyle:FinalClass")
93 public class BrokerFacade implements Closeable {
94 private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
95 private static final BrokerFacade INSTANCE = new BrokerFacade();
97 private volatile DOMRpcService rpcService;
99 private DOMDataBroker domDataBroker;
100 private DOMNotificationService domNotification;
101 private ControllerContext controllerContext;
103 // Temporary until the static instance is removed.
105 private BrokerFacade() {
108 private BrokerFacade(DOMRpcService rpcService, DOMDataBroker domDataBroker, DOMNotificationService domNotification,
109 ControllerContext controllerContext) {
110 this.rpcService = rpcService;
111 this.domDataBroker = domDataBroker;
112 this.domNotification = domNotification;
113 this.controllerContext = controllerContext;
117 public static BrokerFacade getInstance() {
118 return BrokerFacade.INSTANCE;
121 public static BrokerFacade newInstance(DOMRpcService rpcService, DOMDataBroker domDataBroker,
122 DOMNotificationService domNotification, ControllerContext controllerContext) {
123 INSTANCE.rpcService = rpcService;
124 INSTANCE.domDataBroker = domDataBroker;
125 INSTANCE.controllerContext = controllerContext;
126 INSTANCE.domNotification = domNotification;
128 //return new BrokerFacade(pcService, domDataBroker, controllerContext);
132 public void close() {
133 domDataBroker = null;
136 private void checkPreconditions() {
137 if (this.domDataBroker == null) {
138 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
143 * Read config data by path.
149 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
150 return readConfigurationData(path, null);
154 * Read config data by path.
159 * value of with-defaults parameter
162 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
163 checkPreconditions();
164 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
165 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
170 * Read config data from mount point by path.
173 * mount point for reading data
178 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
179 final YangInstanceIdentifier path) {
180 return readConfigurationData(mountPoint, path, null);
184 * Read config data from mount point by path.
187 * mount point for reading data
191 * value of with-defaults parameter
194 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
195 final String withDefa) {
196 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
197 if (domDataBrokerService.isPresent()) {
198 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
199 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
202 final String errMsg = "DOM data broker service isn't available for mount point " + path;
204 throw new RestconfDocumentedException(errMsg);
208 * Read operational data by path.
214 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
215 checkPreconditions();
217 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
218 return readDataViaTransaction(tx, OPERATIONAL, path);
223 * Read operational data from mount point by path.
226 * mount point for reading data
231 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
232 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
233 if (domDataBrokerService.isPresent()) {
234 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
235 return readDataViaTransaction(tx, OPERATIONAL, path);
238 final String errMsg = "DOM data broker service isn't available for mount point " + path;
240 throw new RestconfDocumentedException(errMsg);
244 * <b>PUT configuration data</b>
247 * Prepare result(status) for PUT operation and PUT data via transaction.
248 * Return wrapped status and future from PUT.
250 * @param globalSchema
251 * used by merge parents (if contains list)
260 * @return wrapper of status and future of PUT
262 public PutResult commitConfigurationDataPut(
263 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
264 final String insert, final String point) {
265 Preconditions.checkNotNull(globalSchema);
266 Preconditions.checkNotNull(path);
267 Preconditions.checkNotNull(payload);
269 checkPreconditions();
271 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
272 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
274 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
275 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
276 return new PutResult(status, future);
280 * <b>PUT configuration data (Mount point)</b>
283 * Prepare result(status) for PUT operation and PUT data via transaction.
284 * Return wrapped status and future from PUT.
287 * mount point for getting transaction for operation and schema
288 * context for merging parents(if contains list)
297 * @return wrapper of status and future of PUT
299 public PutResult commitMountPointDataPut(
300 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
301 final String insert, final String point) {
302 Preconditions.checkNotNull(mountPoint);
303 Preconditions.checkNotNull(path);
304 Preconditions.checkNotNull(payload);
306 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
307 if (domDataBrokerService.isPresent()) {
308 final DOMDataReadWriteTransaction newReadWriteTransaction =
309 domDataBrokerService.get().newReadWriteTransaction();
310 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
311 ? Status.OK : Status.CREATED;
312 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
313 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
315 return new PutResult(status, future);
317 final String errMsg = "DOM data broker service isn't available for mount point " + path;
319 throw new RestconfDocumentedException(errMsg);
322 public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
324 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
326 // get new transaction and schema context on server or on mounted device
327 final SchemaContext schemaContext;
328 final DOMDataReadWriteTransaction patchTransaction;
329 if (mountPoint == null) {
330 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
331 patchTransaction = this.domDataBroker.newReadWriteTransaction();
333 schemaContext = mountPoint.getSchemaContext();
335 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
337 if (optional.isPresent()) {
338 patchTransaction = optional.get().newReadWriteTransaction();
340 // if mount point does not have broker it is not possible to continue and global error is reported
341 LOG.error("Http Patch {} has failed - device {} does not support broker service",
342 patchContext.getPatchId(), mountPoint.getIdentifier());
343 return new PatchStatusContext(
344 patchContext.getPatchId(),
347 ImmutableList.of(new RestconfError(
348 ErrorType.APPLICATION,
349 ErrorTag.OPERATION_FAILED,
350 "DOM data broker service isn't available for mount point "
351 + mountPoint.getIdentifier()))
356 final List<PatchStatusEntity> editCollection = new ArrayList<>();
357 List<RestconfError> editErrors;
358 boolean withoutError = true;
360 for (final PatchEntity patchEntity : patchContext.getData()) {
361 final PatchEditOperation operation = patchEntity.getOperation();
366 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
367 patchEntity.getNode(), schemaContext);
368 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
369 } catch (final RestconfDocumentedException e) {
370 LOG.error("Error call http Patch operation {} on target {}",
372 patchEntity.getTargetNode().toString());
374 editErrors = new ArrayList<>();
375 editErrors.addAll(e.getErrors());
376 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
377 withoutError = false;
384 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
385 .getTargetNode(), patchEntity.getNode(), schemaContext);
386 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
387 } catch (final RestconfDocumentedException e) {
388 LOG.error("Error call http Patch operation {} on target {}",
390 patchEntity.getTargetNode().toString());
392 editErrors = new ArrayList<>();
393 editErrors.addAll(e.getErrors());
394 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
395 withoutError = false;
403 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
405 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
406 } catch (final RestconfDocumentedException e) {
407 LOG.error("Error call http Patch operation {} on target {}",
409 patchEntity.getTargetNode().toString());
411 editErrors = new ArrayList<>();
412 editErrors.addAll(e.getErrors());
413 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
414 withoutError = false;
421 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
422 patchEntity.getNode(), schemaContext);
423 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
424 } catch (final RestconfDocumentedException e) {
425 LOG.error("Error call http Patch operation {} on target {}",
427 patchEntity.getTargetNode().toString());
429 editErrors = new ArrayList<>();
430 editErrors.addAll(e.getErrors());
431 editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
432 withoutError = false;
437 LOG.error("Unsupported http Patch operation {} on target {}",
439 patchEntity.getTargetNode().toString());
444 // if errors then cancel transaction and return error status
446 patchTransaction.cancel();
447 return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
450 // if no errors commit transaction
451 final CountDownLatch waiter = new CountDownLatch(1);
452 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
453 final PatchStatusContextHelper status = new PatchStatusContextHelper();
455 Futures.addCallback(future, new FutureCallback<Void>() {
457 public void onSuccess(@Nullable final Void result) {
458 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
464 public void onFailure(final Throwable throwable) {
465 // if commit failed it is global error
466 LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
467 status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
468 false, ImmutableList.of(
469 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
472 }, MoreExecutors.directExecutor());
475 return status.getStatus();
478 // POST configuration
479 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
480 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
481 final String insert, final String point) {
482 checkPreconditions();
483 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
484 globalSchema, insert, point);
487 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
488 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
489 final String insert, final String point) {
490 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
491 if (domDataBrokerService.isPresent()) {
492 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
493 payload, mountPoint.getSchemaContext(), insert, point);
495 final String errMsg = "DOM data broker service isn't available for mount point " + path;
497 throw new RestconfDocumentedException(errMsg);
500 // DELETE configuration
501 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
502 final YangInstanceIdentifier path) {
503 checkPreconditions();
504 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
507 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
508 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
509 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
510 if (domDataBrokerService.isPresent()) {
511 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
513 final String errMsg = "DOM data broker service isn't available for mount point " + path;
515 throw new RestconfDocumentedException(errMsg);
519 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
520 final NormalizedNode<?, ?> input) {
521 checkPreconditions();
522 if (this.rpcService == null) {
523 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
525 LOG.trace("Invoke RPC {} with input: {}", type, input);
526 return this.rpcService.invokeRpc(type, input);
529 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
530 final ListenerAdapter listener) {
531 checkPreconditions();
533 if (listener.isListening()) {
537 final YangInstanceIdentifier path = listener.getPath();
538 DOMDataTreeChangeService changeService = (DOMDataTreeChangeService)
539 this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
540 if (changeService == null) {
541 throw new UnsupportedOperationException("DOMDataBroker does not support the DOMDataTreeChangeService"
542 + this.domDataBroker);
544 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(datastore, path);
545 ListenerRegistration<ListenerAdapter> registration =
546 changeService.registerDataTreeChangeListener(root, listener);
547 listener.setRegistration(registration);
550 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
551 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
552 return readDataViaTransaction(transaction, datastore, path, null);
555 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
556 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
557 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
560 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
561 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
562 prepareDataByParamWithDef(optional.get(), path, withDefa);
563 } catch (ReadFailedException e) {
564 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
565 for (final RpcError error : e.getErrorList()) {
566 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
567 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
568 throw new RestconfDocumentedException(
571 ErrorTag.RESOURCE_DENIED_TRANSPORT, e);
574 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
578 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
579 final YangInstanceIdentifier path, final String withDefa) {
589 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
592 final SchemaContext ctx = controllerContext.getGlobalSchema();
593 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
594 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
595 if (result instanceof ContainerNode) {
596 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
597 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
598 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
599 return builder.build();
602 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
603 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
604 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
605 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
606 return builder.build();
609 private void buildMapEntryBuilder(
610 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
611 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
612 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
613 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
614 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
615 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
616 if (child instanceof ContainerNode) {
617 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
618 Builders.containerBuilder((ContainerSchemaNode) childSchema);
619 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
620 builder.withChild(childBuilder.build());
621 } else if (child instanceof MapNode) {
622 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
623 Builders.mapBuilder((ListSchemaNode) childSchema);
624 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
625 ((ListSchemaNode) childSchema).getKeyDefinition());
626 builder.withChild(childBuilder.build());
627 } else if (child instanceof LeafNode) {
628 final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
629 final Object nodeVal = ((LeafNode<?>) child).getValue();
630 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
631 Builders.leafBuilder((LeafSchemaNode) childSchema);
632 if (keys.contains(child.getNodeType())) {
633 leafBuilder.withValue(((LeafNode<?>) child).getValue());
634 builder.withChild(leafBuilder.build());
637 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
638 leafBuilder.withValue(((LeafNode<?>) child).getValue());
639 builder.withChild(leafBuilder.build());
642 if (defaultVal != null && defaultVal.equals(nodeVal)) {
643 leafBuilder.withValue(((LeafNode<?>) child).getValue());
644 builder.withChild(leafBuilder.build());
652 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
653 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
654 final List<QName> keys) {
655 for (final MapEntryNode mapEntryNode : result.getValue()) {
656 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
657 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
658 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
659 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
660 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
661 builder.withChild(mapEntryBuilder.build());
665 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
666 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
667 final YangInstanceIdentifier actualPath, final boolean trim) {
668 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
669 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
670 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
671 if (child instanceof ContainerNode) {
672 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
673 Builders.containerBuilder((ContainerSchemaNode) childSchema);
674 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
675 builder.withChild(builderChild.build());
676 } else if (child instanceof MapNode) {
677 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
678 Builders.mapBuilder((ListSchemaNode) childSchema);
679 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
680 ((ListSchemaNode) childSchema).getKeyDefinition());
681 builder.withChild(childBuilder.build());
682 } else if (child instanceof LeafNode) {
683 final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
684 final Object nodeVal = ((LeafNode<?>) child).getValue();
685 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
686 Builders.leafBuilder((LeafSchemaNode) childSchema);
688 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
689 leafBuilder.withValue(((LeafNode<?>) child).getValue());
690 builder.withChild(leafBuilder.build());
693 if (defaultVal != null && defaultVal.equals(nodeVal)) {
694 leafBuilder.withValue(((LeafNode<?>) child).getValue());
695 builder.withChild(leafBuilder.build());
703 * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
705 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
706 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
707 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
708 final String insert, final String point) {
709 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
710 postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
711 return rwTransaction.submit();
715 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
717 private void postDataWithinTransaction(
718 final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
719 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
720 LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
721 postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
724 private void postData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
725 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
726 final SchemaContext schemaContext, final String insert, final String point) {
727 if (insert == null) {
728 makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
732 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
733 checkItemDoesNotExists(rwTransaction, datastore, path);
736 if (schemaNode instanceof ListSchemaNode) {
737 final OrderedMapNode readList =
738 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
739 if (readList == null || readList.getValue().isEmpty()) {
740 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
742 rwTransaction.delete(datastore, path.getParent().getParent());
743 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
744 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
748 final OrderedLeafSetNode<?> readLeafList =
749 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
750 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
751 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
753 rwTransaction.delete(datastore, path.getParent());
754 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
755 makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
761 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
764 if (schemaNode instanceof ListSchemaNode) {
765 final OrderedMapNode readList =
766 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
767 if (readList == null || readList.getValue().isEmpty()) {
768 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
770 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
775 final OrderedLeafSetNode<?> readLeafList =
776 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
777 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
778 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
780 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
786 if (schemaNode instanceof ListSchemaNode) {
787 final OrderedMapNode readList =
788 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
789 if (readList == null || readList.getValue().isEmpty()) {
790 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
792 insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
797 final OrderedLeafSetNode<?> readLeafList =
798 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
799 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
800 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
802 insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
803 readLeafList, false);
808 throw new RestconfDocumentedException(
809 "Used bad value of insert parameter. Possible values are first, last, before or after, "
810 + "but was: " + insert);
814 private void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
815 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
816 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
817 final boolean before) {
818 rwTransaction.delete(datastore, path.getParent().getParent());
819 final InstanceIdentifierContext<?> instanceIdentifier = controllerContext.toInstanceIdentifier(point);
820 int lastItemPosition = 0;
821 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
822 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
830 int lastInsertedPosition = 0;
831 final NormalizedNode<?, ?> emptySubtree =
832 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
833 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
834 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
835 if (lastInsertedPosition == lastItemPosition) {
836 checkItemDoesNotExists(rwTransaction, datastore, path);
837 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
839 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
840 checkItemDoesNotExists(rwTransaction, datastore, childPath);
841 rwTransaction.put(datastore, childPath, nodeChild);
842 lastInsertedPosition++;
846 private void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
847 final LogicalDatastoreType datastore,
848 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
849 final String point, final MapNode readList, final boolean before) {
850 rwTransaction.delete(datastore, path.getParent().getParent());
851 final InstanceIdentifierContext<?> instanceIdentifier = controllerContext.toInstanceIdentifier(point);
852 int lastItemPosition = 0;
853 for (final MapEntryNode mapEntryNode : readList.getValue()) {
854 if (mapEntryNode.getIdentifier()
855 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
863 int lastInsertedPosition = 0;
864 final NormalizedNode<?, ?> emptySubtree =
865 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
866 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
867 for (final MapEntryNode mapEntryNode : readList.getValue()) {
868 if (lastInsertedPosition == lastItemPosition) {
869 checkItemDoesNotExists(rwTransaction, datastore, path);
870 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
872 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
873 checkItemDoesNotExists(rwTransaction, datastore, childPath);
874 rwTransaction.put(datastore, childPath, mapEntryNode);
875 lastInsertedPosition++;
879 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
880 final YangInstanceIdentifier parent = path.getParent();
881 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
882 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
884 if (dataSchemaNode instanceof ListSchemaNode) {
885 if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
886 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
888 return dataSchemaNode;
890 if (dataSchemaNode instanceof LeafListSchemaNode) {
891 if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
892 throw new RestconfDocumentedException(
893 "Insert parameter can be used only with ordered-by user leaf-list.");
895 return dataSchemaNode;
897 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
900 private static void makeNormalPost(final DOMDataReadWriteTransaction rwTransaction,
901 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
902 final SchemaContext schemaContext) {
903 final Collection<? extends NormalizedNode<?, ?>> children;
904 if (payload instanceof MapNode) {
905 children = ((MapNode) payload).getValue();
906 } else if (payload instanceof LeafSetNode) {
907 children = ((LeafSetNode<?>) payload).getValue();
909 simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
913 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
914 if (children.isEmpty()) {
915 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
916 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
920 // Kick off batch existence check first...
921 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
923 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
924 // result of the existence checks...
925 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
926 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
927 for (final NormalizedNode<?, ?> child : children) {
928 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
929 // as that would allow us to skip the existence checks
930 rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
933 // ... finally collect existence checks and abort the transaction if any of them failed.
934 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
936 failure = check.getFailure();
937 } catch (InterruptedException e) {
938 rwTransaction.cancel();
939 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
942 if (failure != null) {
943 rwTransaction.cancel();
944 final ReadFailedException e = failure.getValue();
946 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
947 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
950 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
955 private static void simplePostPut(final DOMDataReadWriteTransaction rwTransaction,
956 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
957 final SchemaContext schemaContext) {
958 checkItemDoesNotExists(rwTransaction, datastore, path);
959 ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
960 rwTransaction.put(datastore, path, payload);
963 private static boolean doesItemExist(final DOMDataReadWriteTransaction rwTransaction,
964 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
966 return rwTransaction.exists(store, path).checkedGet();
967 } catch (ReadFailedException e) {
968 rwTransaction.cancel();
969 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
970 e, e.getErrorList());
975 * Check if item already exists. Throws error if it does NOT already exist.
976 * @param rwTransaction Current transaction
977 * @param store Used datastore
978 * @param path Path to item to verify its existence
980 private static void checkItemExists(final DOMDataReadWriteTransaction rwTransaction,
981 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
982 if (!doesItemExist(rwTransaction, store, path)) {
983 final String errMsg = "Operation via Restconf was not executed because data does not exist";
984 LOG.trace("{}:{}", errMsg, path);
985 rwTransaction.cancel();
986 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
987 ErrorTag.DATA_MISSING);
992 * Check if item does NOT already exist. Throws error if it already exists.
993 * @param rwTransaction Current transaction
994 * @param store Used datastore
995 * @param path Path to item to verify its existence
997 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rwTransaction,
998 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
999 if (doesItemExist(rwTransaction, store, path)) {
1000 final String errMsg = "Operation via Restconf was not executed because data already exists";
1001 LOG.trace("{}:{}", errMsg, path);
1002 rwTransaction.cancel();
1003 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
1004 ErrorTag.DATA_EXISTS);
1009 * PUT data and submit {@link DOMDataReadWriteTransaction}.
1016 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1017 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1018 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1019 final String insert, final String point) {
1020 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1021 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1022 return readWriteTransaction.submit();
1026 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
1028 private void putDataWithinTransaction(
1029 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1030 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1031 LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1032 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1035 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1036 private void putData(final DOMDataReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
1037 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1038 final String insert, final String point) {
1039 if (insert == null) {
1040 makePut(rwTransaction, datastore, path, payload, schemaContext);
1044 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1045 checkItemDoesNotExists(rwTransaction, datastore, path);
1048 if (schemaNode instanceof ListSchemaNode) {
1049 final OrderedMapNode readList =
1050 (OrderedMapNode) this.readConfigurationData(path.getParent());
1051 if (readList == null || readList.getValue().isEmpty()) {
1052 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1054 rwTransaction.delete(datastore, path.getParent());
1055 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1056 makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
1059 final OrderedLeafSetNode<?> readLeafList =
1060 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1061 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1062 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1064 rwTransaction.delete(datastore, path.getParent());
1065 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1066 makePut(rwTransaction, datastore, path.getParent(), readLeafList,
1072 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1075 if (schemaNode instanceof ListSchemaNode) {
1076 final OrderedMapNode readList =
1077 (OrderedMapNode) this.readConfigurationData(path.getParent());
1078 if (readList == null || readList.getValue().isEmpty()) {
1079 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1081 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1085 final OrderedLeafSetNode<?> readLeafList =
1086 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1087 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1088 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1090 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1091 readLeafList, true);
1096 if (schemaNode instanceof ListSchemaNode) {
1097 final OrderedMapNode readList =
1098 (OrderedMapNode) this.readConfigurationData(path.getParent());
1099 if (readList == null || readList.getValue().isEmpty()) {
1100 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1102 insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1106 final OrderedLeafSetNode<?> readLeafList =
1107 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1108 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1109 simplePut(datastore, path, rwTransaction, schemaContext, payload);
1111 insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
1112 readLeafList, false);
1117 throw new RestconfDocumentedException(
1118 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1123 private void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1124 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1125 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1126 final boolean before) {
1127 tx.delete(datastore, path.getParent());
1128 final InstanceIdentifierContext<?> instanceIdentifier = controllerContext.toInstanceIdentifier(point);
1130 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1131 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1140 final NormalizedNode<?, ?> emptySubtree =
1141 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1142 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1143 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1144 if (index2 == index1) {
1145 simplePut(datastore, path, tx, schemaContext, payload);
1147 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1148 tx.put(datastore, childPath, nodeChild);
1153 private void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1154 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1155 final String point, final OrderedMapNode readList, final boolean before) {
1156 tx.delete(datastore, path.getParent());
1157 final InstanceIdentifierContext<?> instanceIdentifier = controllerContext.toInstanceIdentifier(point);
1159 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1160 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1169 final NormalizedNode<?, ?> emptySubtree =
1170 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1171 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1172 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1173 if (index2 == index1) {
1174 simplePut(datastore, path, tx, schemaContext, payload);
1176 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1177 tx.put(datastore, childPath, mapEntryNode);
1182 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1183 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1184 if (payload instanceof MapNode) {
1185 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1186 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1187 ensureParentsByMerge(datastore, path, tx, schemaContext);
1188 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1189 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1190 tx.put(datastore, childPath, child);
1193 simplePut(datastore, path, tx, schemaContext, payload);
1197 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1198 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1199 ensureParentsByMerge(datastore, path, tx, schemaContext);
1200 tx.put(datastore, path, payload);
1203 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1204 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1205 final YangInstanceIdentifier path) {
1206 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1207 checkItemExists(readWriteTransaction, datastore, path);
1208 readWriteTransaction.delete(datastore, path);
1209 return readWriteTransaction.submit();
1212 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1213 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1214 LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
1215 tx.delete(datastore, path);
1218 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1219 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1220 final SchemaContext schemaContext) {
1221 LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
1222 ensureParentsByMerge(datastore, path, tx, schemaContext);
1224 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1225 // OpenDaylight should not change it.
1226 tx.merge(datastore, path, payload);
1229 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1230 checkPreconditions();
1232 if (listener.isListening()) {
1236 final SchemaPath path = listener.getSchemaPath();
1237 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1238 .registerNotificationListener(listener, path);
1240 listener.setRegistration(registration);
1243 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1244 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1245 final SchemaContext schemaContext) {
1246 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1247 YangInstanceIdentifier rootNormalizedPath = null;
1249 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1251 while (it.hasNext()) {
1252 final PathArgument pathArgument = it.next();
1253 if (rootNormalizedPath == null) {
1254 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1258 normalizedPathWithoutChildArgs.add(pathArgument);
1262 if (normalizedPathWithoutChildArgs.isEmpty()) {
1266 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1268 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1269 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1270 tx.merge(store, rootNormalizedPath, parentStructure);
1273 private static final class PatchStatusContextHelper {
1274 PatchStatusContext status;
1276 public PatchStatusContext getStatus() {
1280 public void setStatus(final PatchStatusContext status) {
1281 this.status = status;