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.concurrent.CountDownLatch;
24 import javax.annotation.Nullable;
25 import javax.ws.rs.core.Response.Status;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
36 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
37 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
41 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
42 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
43 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
44 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
45 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
46 import org.opendaylight.yangtools.concepts.ListenerRegistration;
47 import org.opendaylight.yangtools.yang.common.QName;
48 import org.opendaylight.yangtools.yang.common.RpcError;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
53 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
55 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
63 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
64 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
65 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
66 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
67 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
68 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
69 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
70 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
76 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 public class BrokerFacade {
81 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
83 private final static BrokerFacade INSTANCE = new BrokerFacade();
84 private volatile DOMRpcService rpcService;
85 private volatile ConsumerSession context;
86 private DOMDataBroker domDataBroker;
87 private DOMNotificationService domNotification;
89 private BrokerFacade() {}
91 public void setRpcService(final DOMRpcService router) {
92 this.rpcService = router;
95 public void setDomNotificationService(final DOMNotificationService domNotification) {
96 this.domNotification = domNotification;
99 public void setContext(final ConsumerSession context) {
100 this.context = context;
103 public static BrokerFacade getInstance() {
104 return BrokerFacade.INSTANCE;
107 private void checkPreconditions() {
108 if (this.context == null || this.domDataBroker == null) {
109 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
114 * Read config data by path
120 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
121 return readConfigurationData(path, null);
125 * Read config data by path
130 * - value of with-defaults parameter
133 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
134 checkPreconditions();
135 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path, withDefa);
139 * Read config data from mount point by path.
142 * - mount point for reading data
147 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
148 final YangInstanceIdentifier path) {
149 return readConfigurationData(mountPoint, path, null);
153 * Read config data from mount point by path.
156 * - mount point for reading data
160 * - value of with-defaults parameter
163 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
164 final String withDefa) {
165 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
166 if (domDataBrokerService.isPresent()) {
167 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path,
170 final String errMsg = "DOM data broker service isn't available for mount point " + path;
172 throw new RestconfDocumentedException(errMsg);
176 * Read operational data by path.
182 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
183 checkPreconditions();
184 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
188 * Read operational data from mount point by path.
191 * - mount point for reading data
196 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
197 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
198 if (domDataBrokerService.isPresent()) {
199 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
201 final String errMsg = "DOM data broker service isn't available for mount point " + path;
203 throw new RestconfDocumentedException(errMsg);
207 * <b>PUT configuration data</b>
209 * Prepare result(status) for PUT operation and PUT data via transaction.
210 * Return wrapped status and future from PUT.
212 * @param globalSchema
213 * - used by merge parents (if contains list)
220 * @return wrapper of status and future of PUT
222 public PutResult commitConfigurationDataPut(
223 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
224 final String insert, final String point) {
225 Preconditions.checkNotNull(globalSchema);
226 Preconditions.checkNotNull(path);
227 Preconditions.checkNotNull(payload);
229 checkPreconditions();
231 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
232 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
234 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
235 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
236 return new PutResult(status, future);
240 * <b>PUT configuration data (Mount point)</b>
242 * Prepare result(status) for PUT operation and PUT data via transaction.
243 * Return wrapped status and future from PUT.
246 * - mount point for getting transaction for operation and schema
247 * context for merging parents(if contains list)
254 * @return wrapper of status and future of PUT
256 public PutResult commitMountPointDataPut(
257 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
258 final String insert, final String point) {
259 Preconditions.checkNotNull(mountPoint);
260 Preconditions.checkNotNull(path);
261 Preconditions.checkNotNull(payload);
263 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
264 if (domDataBrokerService.isPresent()) {
265 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
266 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
267 ? Status.OK : Status.CREATED;
268 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
269 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
271 return new PutResult(status, future);
273 final String errMsg = "DOM data broker service isn't available for mount point " + path;
275 throw new RestconfDocumentedException(errMsg);
278 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
279 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
281 // get new transaction and schema context on server or on mounted device
282 final SchemaContext schemaContext;
283 final DOMDataReadWriteTransaction patchTransaction;
284 if (mountPoint == null) {
285 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
286 patchTransaction = this.domDataBroker.newReadWriteTransaction();
288 schemaContext = mountPoint.getSchemaContext();
290 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
292 if (optional.isPresent()) {
293 patchTransaction = optional.get().newReadWriteTransaction();
295 // if mount point does not have broker it is not possible to continue and global error is reported
296 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
297 patchContext.getPatchId(), mountPoint.getIdentifier());
298 return new PATCHStatusContext(
299 patchContext.getPatchId(),
302 ImmutableList.of(new RestconfError(
303 ErrorType.APPLICATION,
304 ErrorTag.OPERATION_FAILED,
305 "DOM data broker service isn't available for mount point "
306 + mountPoint.getIdentifier()))
311 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
312 List<RestconfError> editErrors;
313 boolean withoutError = true;
315 for (final PATCHEntity patchEntity : patchContext.getData()) {
316 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
322 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
323 patchEntity.getNode(), schemaContext);
324 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
325 } catch (final RestconfDocumentedException e) {
326 LOG.error("Error call http PATCH operation {} on target {}",
328 patchEntity.getTargetNode().toString());
330 editErrors = new ArrayList<>();
331 editErrors.addAll(e.getErrors());
332 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
333 withoutError = false;
340 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
341 .getTargetNode(), patchEntity.getNode(), schemaContext);
342 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
343 } catch (final RestconfDocumentedException e) {
344 LOG.error("Error call http PATCH operation {} on target {}",
346 patchEntity.getTargetNode().toString());
348 editErrors = new ArrayList<>();
349 editErrors.addAll(e.getErrors());
350 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
351 withoutError = false;
358 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
360 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
361 } catch (final RestconfDocumentedException e) {
362 LOG.error("Error call http PATCH operation {} on target {}",
364 patchEntity.getTargetNode().toString());
366 editErrors = new ArrayList<>();
367 editErrors.addAll(e.getErrors());
368 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
369 withoutError = false;
376 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
378 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
379 } catch (final RestconfDocumentedException e) {
380 LOG.error("Error call http PATCH operation {} on target {}",
382 patchEntity.getTargetNode().toString());
384 editErrors = new ArrayList<>();
385 editErrors.addAll(e.getErrors());
386 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
387 withoutError = false;
394 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
395 patchEntity.getNode(), schemaContext);
396 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
397 } catch (final RestconfDocumentedException e) {
398 LOG.error("Error call http PATCH operation {} on target {}",
400 patchEntity.getTargetNode().toString());
402 editErrors = new ArrayList<>();
403 editErrors.addAll(e.getErrors());
404 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
405 withoutError = false;
410 LOG.error("Unsupported http PATCH operation {} on target {}",
412 patchEntity.getTargetNode().toString());
417 // if errors then cancel transaction and return error status
419 patchTransaction.cancel();
420 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
423 // if no errors commit transaction
424 final CountDownLatch waiter = new CountDownLatch(1);
425 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
426 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
428 Futures.addCallback(future, new FutureCallback<Void>() {
430 public void onSuccess(@Nullable final Void result) {
431 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
437 public void onFailure(final Throwable t) {
438 // if commit failed it is global error
439 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
440 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
441 false, ImmutableList.of(
442 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
448 return status.getStatus();
451 // POST configuration
452 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
453 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
454 final String insert, final String point) {
455 checkPreconditions();
456 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
457 globalSchema, insert, point);
460 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
461 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
462 final String insert, final String point) {
463 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
464 if (domDataBrokerService.isPresent()) {
465 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
466 payload, mountPoint.getSchemaContext(), insert, point);
468 final String errMsg = "DOM data broker service isn't available for mount point " + path;
470 throw new RestconfDocumentedException(errMsg);
473 // DELETE configuration
474 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
475 final YangInstanceIdentifier path) {
476 checkPreconditions();
477 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
480 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
481 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
482 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
483 if (domDataBrokerService.isPresent()) {
484 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
486 final String errMsg = "DOM data broker service isn't available for mount point " + path;
488 throw new RestconfDocumentedException(errMsg);
492 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
493 checkPreconditions();
494 if (this.rpcService == null) {
495 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
497 LOG.trace("Invoke RPC {} with input: {}", type, input);
498 return this.rpcService.invokeRpc(type, input);
501 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
502 final ListenerAdapter listener) {
503 checkPreconditions();
505 if (listener.isListening()) {
509 final YangInstanceIdentifier path = listener.getPath();
510 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
511 datastore, path, listener, scope);
513 listener.setRegistration(registration);
516 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
517 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
518 return readDataViaTransaction(transaction, datastore, path, null);
521 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
522 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
523 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
526 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
527 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
528 prepareDataByParamWithDef(optional.get(), path, withDefa);
529 } catch (ReadFailedException e) {
530 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
531 for (final RpcError error : e.getErrorList()) {
532 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
533 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
534 throw new RestconfDocumentedException(
537 ErrorTag.RESOURCE_DENIED_TRANSPORT);
540 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
544 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
545 final YangInstanceIdentifier path, final String withDefa) {
555 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
558 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
559 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
560 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
561 if (result instanceof ContainerNode) {
562 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
563 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
564 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
565 return builder.build();
568 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
569 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
570 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
571 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
572 return builder.build();
575 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
576 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
577 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
578 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
579 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
580 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
581 if (child instanceof ContainerNode) {
582 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
583 Builders.containerBuilder((ContainerSchemaNode) childSchema);
584 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
585 builder.withChild(childBuilder.build());
586 } else if (child instanceof MapNode) {
587 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
588 Builders.mapBuilder((ListSchemaNode) childSchema);
589 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
590 ((ListSchemaNode) childSchema).getKeyDefinition());
591 builder.withChild(childBuilder.build());
592 } else if (child instanceof LeafNode) {
593 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
594 final String nodeVal = ((LeafNode<String>) child).getValue();
595 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
596 Builders.leafBuilder((LeafSchemaNode) childSchema);
597 if (keys.contains(child.getNodeType())) {
598 leafBuilder.withValue(((LeafNode) child).getValue());
599 builder.withChild(leafBuilder.build());
602 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
603 leafBuilder.withValue(((LeafNode) child).getValue());
604 builder.withChild(leafBuilder.build());
607 if (defaultVal != null && defaultVal.equals(nodeVal)) {
608 leafBuilder.withValue(((LeafNode) child).getValue());
609 builder.withChild(leafBuilder.build());
617 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
618 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
619 final List<QName> keys) {
620 for (final MapEntryNode mapEntryNode : result.getValue()) {
621 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
622 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
623 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
624 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
625 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
626 builder.withChild(mapEntryBuilder.build());
630 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
631 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
632 final YangInstanceIdentifier actualPath, final boolean trim) {
633 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
634 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
635 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
636 if(child instanceof ContainerNode){
637 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
638 Builders.containerBuilder((ContainerSchemaNode) childSchema);
639 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
640 builder.withChild(builderChild.build());
641 } else if (child instanceof MapNode) {
642 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
643 Builders.mapBuilder((ListSchemaNode) childSchema);
644 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
645 ((ListSchemaNode) childSchema).getKeyDefinition());
646 builder.withChild(childBuilder.build());
647 } else if (child instanceof LeafNode) {
648 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
649 final String nodeVal = ((LeafNode<String>) child).getValue();
650 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
651 Builders.leafBuilder((LeafSchemaNode) childSchema);
653 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
654 leafBuilder.withValue(((LeafNode) child).getValue());
655 builder.withChild(leafBuilder.build());
658 if (defaultVal != null && defaultVal.equals(nodeVal)) {
659 leafBuilder.withValue(((LeafNode) child).getValue());
660 builder.withChild(leafBuilder.build());
668 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
670 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
671 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
672 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
673 final String insert, final String point) {
674 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
675 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
676 return rWTransaction.submit();
680 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
682 private void postDataWithinTransaction(
683 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
684 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
685 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
686 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
689 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
690 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
691 final SchemaContext schemaContext, final String insert, final String point) {
692 if (insert == null) {
693 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
697 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
698 checkItemDoesNotExists(rWTransaction, datastore, path);
701 if(schemaNode instanceof ListSchemaNode){
702 final OrderedMapNode readList =
703 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
704 if (readList == null || readList.getValue().isEmpty()) {
705 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
707 rWTransaction.delete(datastore, path.getParent().getParent());
708 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
709 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
713 final OrderedLeafSetNode<?> readLeafList =
714 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
715 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
716 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
718 rWTransaction.delete(datastore, path.getParent());
719 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
720 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
726 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
729 if(schemaNode instanceof ListSchemaNode){
730 final OrderedMapNode readList =
731 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
732 if (readList == null || readList.getValue().isEmpty()) {
733 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
735 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
740 final OrderedLeafSetNode<?> readLeafList =
741 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
742 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
743 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
745 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
751 if (schemaNode instanceof ListSchemaNode) {
752 final OrderedMapNode readList =
753 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
754 if (readList == null || readList.getValue().isEmpty()) {
755 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
757 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
762 final OrderedLeafSetNode<?> readLeafList =
763 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
764 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
765 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
767 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
768 readLeafList, false);
773 throw new RestconfDocumentedException(
774 "Used bad value of insert parameter. Possible values are first, last, before or after, "
775 + "but was: " + insert);
779 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
780 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
781 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
782 final boolean before) {
783 rWTransaction.delete(datastore, path.getParent().getParent());
784 final InstanceIdentifierContext<?> instanceIdentifier =
785 ControllerContext.getInstance().toInstanceIdentifier(point);
787 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
788 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
797 final NormalizedNode<?, ?> emptySubtree =
798 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
799 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
800 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
802 checkItemDoesNotExists(rWTransaction, datastore, path);
803 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
805 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
806 checkItemDoesNotExists(rWTransaction, datastore, childPath);
807 rWTransaction.put(datastore, childPath, nodeChild);
812 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
813 final LogicalDatastoreType datastore,
814 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
815 final String point, final MapNode readList, final boolean before) {
816 rWTransaction.delete(datastore, path.getParent().getParent());
817 final InstanceIdentifierContext<?> instanceIdentifier =
818 ControllerContext.getInstance().toInstanceIdentifier(point);
820 for (final MapEntryNode mapEntryNode : readList.getValue()) {
821 if (mapEntryNode.getIdentifier()
822 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
831 final NormalizedNode<?, ?> emptySubtree =
832 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
833 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
834 for (final MapEntryNode mapEntryNode : readList.getValue()) {
836 checkItemDoesNotExists(rWTransaction, datastore, path);
837 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
839 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
840 checkItemDoesNotExists(rWTransaction, datastore, childPath);
841 rWTransaction.put(datastore, childPath, mapEntryNode);
846 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
847 final YangInstanceIdentifier parent = path.getParent();
848 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
849 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
851 if (dataSchemaNode instanceof ListSchemaNode) {
852 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
853 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
855 return dataSchemaNode;
857 if (dataSchemaNode instanceof LeafListSchemaNode) {
858 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
859 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
861 return dataSchemaNode;
863 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
866 private static void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction,
867 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
868 final SchemaContext schemaContext) {
869 final Collection<? extends NormalizedNode<?, ?>> children;
870 if (payload instanceof MapNode) {
871 children = ((MapNode) payload).getValue();
872 } else if (payload instanceof LeafSetNode) {
873 children = ((LeafSetNode<?>) payload).getValue();
875 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
879 // We are putting multiple children, we really need a create() operation, but until we have that we make do
880 // with a two-step process of verifying if the children exist and then putting them in.
881 for (final NormalizedNode<?, ?> child : children) {
882 checkItemDoesNotExists(rWTransaction, datastore, path.node(child.getIdentifier()));
885 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
886 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
887 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
888 for (final NormalizedNode<?, ?> child : children) {
889 rWTransaction.put(datastore, path.node(child.getIdentifier()), child);
893 private static void simplePostPut(final DOMDataReadWriteTransaction rWTransaction,
894 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
895 final SchemaContext schemaContext) {
896 checkItemDoesNotExists(rWTransaction, datastore, path);
897 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
898 rWTransaction.put(datastore, path, payload);
901 private static boolean doesItemExist(final DOMDataReadWriteTransaction rWTransaction,
902 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
904 return rWTransaction.exists(store, path).checkedGet();
905 } catch (ReadFailedException e) {
906 rWTransaction.cancel();
907 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
908 e, e.getErrorList());
913 * Check if item already exists. Throws error if it does NOT already exist.
914 * @param rWTransaction Current transaction
915 * @param store Used datastore
916 * @param path Path to item to verify its existence
918 private static void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
919 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
920 if (!doesItemExist(rWTransaction, store, path)) {
921 final String errMsg = "Operation via Restconf was not executed because data does not exist";
922 LOG.trace("{}:{}", errMsg, path);
923 rWTransaction.cancel();
924 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
925 ErrorTag.DATA_MISSING);
930 * Check if item does NOT already exist. Throws error if it already exists.
931 * @param rWTransaction Current transaction
932 * @param store Used datastore
933 * @param path Path to item to verify its existence
935 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
936 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
937 if (doesItemExist(rWTransaction, store, path)) {
938 final String errMsg = "Operation via Restconf was not executed because data already exists";
939 LOG.trace("{}:{}", errMsg, path);
940 rWTransaction.cancel();
941 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
942 ErrorTag.DATA_EXISTS);
947 * PUT data and submit {@link DOMDataReadWriteTransaction}
952 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
953 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
954 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
955 final String insert, final String point) {
956 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
957 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
958 return readWriteTransaction.submit();
962 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
967 private void putDataWithinTransaction(
968 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
969 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
970 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
971 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
974 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
975 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
976 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
977 final String insert, final String point) {
978 if (insert == null) {
979 makePut(rWTransaction, datastore, path, payload, schemaContext);
981 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
982 checkItemDoesNotExists(rWTransaction, datastore, path);
985 if (schemaNode instanceof ListSchemaNode) {
986 final OrderedMapNode readList =
987 (OrderedMapNode) this.readConfigurationData(path.getParent());
988 if (readList == null || readList.getValue().isEmpty()) {
989 simplePut(datastore, path, rWTransaction, schemaContext, payload);
991 rWTransaction.delete(datastore, path.getParent());
992 simplePut(datastore, path, rWTransaction, schemaContext, payload);
993 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
996 final OrderedLeafSetNode<?> readLeafList =
997 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
998 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
999 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1001 rWTransaction.delete(datastore, path.getParent());
1002 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1003 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1009 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1012 if (schemaNode instanceof ListSchemaNode) {
1013 final OrderedMapNode readList =
1014 (OrderedMapNode) this.readConfigurationData(path.getParent());
1015 if (readList == null || readList.getValue().isEmpty()) {
1016 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1018 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1022 final OrderedLeafSetNode<?> readLeafList =
1023 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1024 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1025 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1027 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1028 readLeafList, true);
1033 if (schemaNode instanceof ListSchemaNode) {
1034 final OrderedMapNode readList =
1035 (OrderedMapNode) this.readConfigurationData(path.getParent());
1036 if (readList == null || readList.getValue().isEmpty()) {
1037 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1039 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1043 final OrderedLeafSetNode<?> readLeafList =
1044 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1045 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1046 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1048 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1049 readLeafList, false);
1054 throw new RestconfDocumentedException(
1055 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1056 + "but was: " + insert);
1061 private static void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1062 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1063 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1064 final boolean before) {
1065 rWTransaction.delete(datastore, path.getParent());
1066 final InstanceIdentifierContext<?> instanceIdentifier =
1067 ControllerContext.getInstance().toInstanceIdentifier(point);
1069 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1070 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1079 final NormalizedNode<?, ?> emptySubtree =
1080 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1081 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1082 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1084 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1086 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1087 rWTransaction.put(datastore, childPath, nodeChild);
1092 private static void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1093 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1094 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1095 final boolean before) {
1096 rWTransaction.delete(datastore, path.getParent());
1097 final InstanceIdentifierContext<?> instanceIdentifier =
1098 ControllerContext.getInstance().toInstanceIdentifier(point);
1100 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1101 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1110 final NormalizedNode<?, ?> emptySubtree =
1111 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1112 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1113 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1115 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1117 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1118 rWTransaction.put(datastore, childPath, mapEntryNode);
1123 private static void makePut(final DOMDataReadWriteTransaction writeTransaction,
1124 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1125 final SchemaContext schemaContext) {
1126 if (payload instanceof MapNode) {
1127 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1128 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1129 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1130 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1131 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1132 writeTransaction.put(datastore, childPath, child);
1135 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1139 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1140 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1141 final NormalizedNode<?, ?> payload) {
1142 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1143 writeTransaction.put(datastore, path, payload);
1146 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1147 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1148 final YangInstanceIdentifier path) {
1149 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1150 checkItemExists(readWriteTransaction, datastore, path);
1151 readWriteTransaction.delete(datastore, path);
1152 return readWriteTransaction.submit();
1155 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction writeTransaction,
1156 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1157 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1158 writeTransaction.delete(datastore, path);
1161 private static void mergeDataWithinTransaction(
1162 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1163 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1164 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1165 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1167 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1168 // OpenDaylight should not change it.
1169 writeTransaction.merge(datastore, path, payload);
1172 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1173 this.domDataBroker = domDataBroker;
1176 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1177 checkPreconditions();
1179 if (listener.isListening()) {
1183 final SchemaPath path = listener.getSchemaPath();
1184 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1185 .registerNotificationListener(listener, path);
1187 listener.setRegistration(registration);
1190 private final class PATCHStatusContextHelper {
1191 PATCHStatusContext status;
1193 public PATCHStatusContext getStatus() {
1197 public void setStatus(final PATCHStatusContext status) {
1198 this.status = status;
1202 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1203 final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx,
1204 final SchemaContext schemaContext) {
1205 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1206 YangInstanceIdentifier rootNormalizedPath = null;
1208 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1210 while (it.hasNext()) {
1211 final PathArgument pathArgument = it.next();
1212 if (rootNormalizedPath == null) {
1213 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1217 normalizedPathWithoutChildArgs.add(pathArgument);
1221 if (normalizedPathWithoutChildArgs.isEmpty()) {
1225 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1227 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1228 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1229 rwTx.merge(store, rootNormalizedPath, parentStructure);