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.Iterator;
21 import java.util.List;
22 import java.util.concurrent.CountDownLatch;
23 import javax.annotation.Nullable;
24 import javax.ws.rs.core.Response.Status;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
29 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
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 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
136 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
141 * Read config data from mount point by path.
144 * - mount point for reading data
149 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
150 final YangInstanceIdentifier path) {
151 return readConfigurationData(mountPoint, path, null);
155 * Read config data from mount point by path.
158 * - mount point for reading data
162 * - value of with-defaults parameter
165 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
166 final String withDefa) {
167 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
168 if (domDataBrokerService.isPresent()) {
169 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
170 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
173 final String errMsg = "DOM data broker service isn't available for mount point " + path;
175 throw new RestconfDocumentedException(errMsg);
179 * Read operational data by path.
185 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
186 checkPreconditions();
188 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
189 return readDataViaTransaction(tx, OPERATIONAL, path);
194 * Read operational data from mount point by path.
197 * - mount point for reading data
202 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
203 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
204 if (domDataBrokerService.isPresent()) {
205 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
206 return readDataViaTransaction(tx, OPERATIONAL, path);
209 final String errMsg = "DOM data broker service isn't available for mount point " + path;
211 throw new RestconfDocumentedException(errMsg);
215 * <b>PUT configuration data</b>
217 * Prepare result(status) for PUT operation and PUT data via transaction.
218 * Return wrapped status and future from PUT.
220 * @param globalSchema
221 * - used by merge parents (if contains list)
228 * @return wrapper of status and future of PUT
230 public PutResult commitConfigurationDataPut(
231 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
232 final String insert, final String point) {
233 Preconditions.checkNotNull(globalSchema);
234 Preconditions.checkNotNull(path);
235 Preconditions.checkNotNull(payload);
237 checkPreconditions();
239 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
240 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
242 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
243 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
244 return new PutResult(status, future);
248 * <b>PUT configuration data (Mount point)</b>
250 * Prepare result(status) for PUT operation and PUT data via transaction.
251 * Return wrapped status and future from PUT.
254 * - mount point for getting transaction for operation and schema
255 * context for merging parents(if contains list)
262 * @return wrapper of status and future of PUT
264 public PutResult commitMountPointDataPut(
265 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
266 final String insert, final String point) {
267 Preconditions.checkNotNull(mountPoint);
268 Preconditions.checkNotNull(path);
269 Preconditions.checkNotNull(payload);
271 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
272 if (domDataBrokerService.isPresent()) {
273 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
274 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
275 ? Status.OK : Status.CREATED;
276 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
277 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
279 return new PutResult(status, future);
281 final String errMsg = "DOM data broker service isn't available for mount point " + path;
283 throw new RestconfDocumentedException(errMsg);
286 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
287 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
289 // get new transaction and schema context on server or on mounted device
290 final SchemaContext schemaContext;
291 final DOMDataReadWriteTransaction patchTransaction;
292 if (mountPoint == null) {
293 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
294 patchTransaction = this.domDataBroker.newReadWriteTransaction();
296 schemaContext = mountPoint.getSchemaContext();
298 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
300 if (optional.isPresent()) {
301 patchTransaction = optional.get().newReadWriteTransaction();
303 // if mount point does not have broker it is not possible to continue and global error is reported
304 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
305 patchContext.getPatchId(), mountPoint.getIdentifier());
306 return new PATCHStatusContext(
307 patchContext.getPatchId(),
310 ImmutableList.of(new RestconfError(
311 ErrorType.APPLICATION,
312 ErrorTag.OPERATION_FAILED,
313 "DOM data broker service isn't available for mount point "
314 + mountPoint.getIdentifier()))
319 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
320 List<RestconfError> editErrors;
321 boolean withoutError = true;
323 for (final PATCHEntity patchEntity : patchContext.getData()) {
324 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
330 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
331 patchEntity.getNode(), schemaContext);
332 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
333 } catch (final RestconfDocumentedException e) {
334 LOG.error("Error call http PATCH operation {} on target {}",
336 patchEntity.getTargetNode().toString());
338 editErrors = new ArrayList<>();
339 editErrors.addAll(e.getErrors());
340 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
341 withoutError = false;
348 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
349 .getTargetNode(), patchEntity.getNode(), schemaContext);
350 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
351 } catch (final RestconfDocumentedException e) {
352 LOG.error("Error call http PATCH operation {} on target {}",
354 patchEntity.getTargetNode().toString());
356 editErrors = new ArrayList<>();
357 editErrors.addAll(e.getErrors());
358 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
359 withoutError = false;
366 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
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 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
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;
402 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
403 patchEntity.getNode(), schemaContext);
404 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
405 } catch (final RestconfDocumentedException e) {
406 LOG.error("Error call http PATCH operation {} on target {}",
408 patchEntity.getTargetNode().toString());
410 editErrors = new ArrayList<>();
411 editErrors.addAll(e.getErrors());
412 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
413 withoutError = false;
418 LOG.error("Unsupported http PATCH operation {} on target {}",
420 patchEntity.getTargetNode().toString());
425 // if errors then cancel transaction and return error status
427 patchTransaction.cancel();
428 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
431 // if no errors commit transaction
432 final CountDownLatch waiter = new CountDownLatch(1);
433 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
434 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
436 Futures.addCallback(future, new FutureCallback<Void>() {
438 public void onSuccess(@Nullable final Void result) {
439 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
445 public void onFailure(final Throwable t) {
446 // if commit failed it is global error
447 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
448 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
449 false, ImmutableList.of(
450 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
456 return status.getStatus();
459 // POST configuration
460 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
461 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
462 final String insert, final String point) {
463 checkPreconditions();
464 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
465 globalSchema, insert, point);
468 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
469 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
470 final String insert, final String point) {
471 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
472 if (domDataBrokerService.isPresent()) {
473 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
474 payload, mountPoint.getSchemaContext(), insert, point);
476 final String errMsg = "DOM data broker service isn't available for mount point " + path;
478 throw new RestconfDocumentedException(errMsg);
481 // DELETE configuration
482 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
483 final YangInstanceIdentifier path) {
484 checkPreconditions();
485 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
488 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
489 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
490 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
491 if (domDataBrokerService.isPresent()) {
492 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
494 final String errMsg = "DOM data broker service isn't available for mount point " + path;
496 throw new RestconfDocumentedException(errMsg);
500 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
501 checkPreconditions();
502 if (this.rpcService == null) {
503 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
505 LOG.trace("Invoke RPC {} with input: {}", type, input);
506 return this.rpcService.invokeRpc(type, input);
509 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
510 final ListenerAdapter listener) {
511 checkPreconditions();
513 if (listener.isListening()) {
517 final YangInstanceIdentifier path = listener.getPath();
518 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
519 datastore, path, listener, scope);
521 listener.setRegistration(registration);
524 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
525 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
526 return readDataViaTransaction(transaction, datastore, path, null);
529 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
530 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
531 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
534 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
535 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
536 prepareDataByParamWithDef(optional.get(), path, withDefa);
537 } catch (ReadFailedException e) {
538 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
539 for (final RpcError error : e.getErrorList()) {
540 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
541 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
542 throw new RestconfDocumentedException(
545 ErrorTag.RESOURCE_DENIED_TRANSPORT);
548 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
552 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
553 final YangInstanceIdentifier path, final String withDefa) {
563 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
566 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
567 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
568 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
569 if (result instanceof ContainerNode) {
570 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
571 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
572 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
573 return builder.build();
575 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
576 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
577 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
578 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
579 return builder.build();
583 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
584 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
585 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
586 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
587 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
588 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
589 if (child instanceof ContainerNode) {
590 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
591 Builders.containerBuilder((ContainerSchemaNode) childSchema);
592 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
593 builder.withChild(childBuilder.build());
594 } else if (child instanceof MapNode) {
595 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
596 Builders.mapBuilder((ListSchemaNode) childSchema);
597 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
598 ((ListSchemaNode) childSchema).getKeyDefinition());
599 builder.withChild(childBuilder.build());
600 } else if (child instanceof LeafNode) {
601 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
602 final String nodeVal = ((LeafNode<String>) child).getValue();
603 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
604 Builders.leafBuilder((LeafSchemaNode) childSchema);
605 if (keys.contains(child.getNodeType())) {
606 leafBuilder.withValue(((LeafNode) child).getValue());
607 builder.withChild(leafBuilder.build());
610 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
611 leafBuilder.withValue(((LeafNode) child).getValue());
612 builder.withChild(leafBuilder.build());
615 if (defaultVal != null && defaultVal.equals(nodeVal)) {
616 leafBuilder.withValue(((LeafNode) child).getValue());
617 builder.withChild(leafBuilder.build());
625 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
626 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
627 final List<QName> keys) {
628 for (final MapEntryNode mapEntryNode : result.getValue()) {
629 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
630 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
631 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
632 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
633 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
634 builder.withChild(mapEntryBuilder.build());
638 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
639 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
640 final YangInstanceIdentifier actualPath, final boolean trim) {
641 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
642 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
643 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
644 if(child instanceof ContainerNode){
645 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
646 Builders.containerBuilder((ContainerSchemaNode) childSchema);
647 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
648 builder.withChild(builderChild.build());
649 } else if (child instanceof MapNode) {
650 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
651 Builders.mapBuilder((ListSchemaNode) childSchema);
652 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
653 ((ListSchemaNode) childSchema).getKeyDefinition());
654 builder.withChild(childBuilder.build());
655 } else if (child instanceof LeafNode) {
656 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
657 final String nodeVal = ((LeafNode<String>) child).getValue();
658 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
659 Builders.leafBuilder((LeafSchemaNode) childSchema);
661 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
662 leafBuilder.withValue(((LeafNode) child).getValue());
663 builder.withChild(leafBuilder.build());
666 if (defaultVal != null && defaultVal.equals(nodeVal)) {
667 leafBuilder.withValue(((LeafNode) child).getValue());
668 builder.withChild(leafBuilder.build());
676 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
678 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
679 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
680 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
681 final String insert, final String point) {
682 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
683 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
684 return rWTransaction.submit();
688 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
690 private void postDataWithinTransaction(
691 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
692 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
693 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
694 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
697 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
698 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
699 final SchemaContext schemaContext, final String insert, final String point) {
700 if (insert == null) {
701 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
703 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
704 checkItemDoesNotExists(rWTransaction, datastore, path);
707 if(schemaNode instanceof ListSchemaNode){
708 final OrderedMapNode readList =
709 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
710 if (readList == null || readList.getValue().isEmpty()) {
711 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
713 rWTransaction.delete(datastore, path.getParent().getParent());
714 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
715 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
719 final OrderedLeafSetNode readLeafList =
720 (OrderedLeafSetNode) readConfigurationData(path.getParent());
721 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
722 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
724 rWTransaction.delete(datastore, path.getParent());
725 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
726 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
732 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
735 if(schemaNode instanceof ListSchemaNode){
736 final OrderedMapNode readList =
737 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
738 if (readList == null || readList.getValue().isEmpty()) {
739 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
741 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
746 final OrderedLeafSetNode<?> readLeafList =
747 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
748 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
749 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
751 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
757 if (schemaNode instanceof ListSchemaNode) {
758 final OrderedMapNode readList =
759 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
760 if (readList == null || readList.getValue().isEmpty()) {
761 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
763 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
768 final OrderedLeafSetNode<?> readLeafList =
769 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
770 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
771 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
773 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
774 readLeafList, false);
779 throw new RestconfDocumentedException(
780 "Used bad value of insert parameter. Possible values are first, last, before or after, "
781 + "but was: " + insert);
786 private void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
787 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
788 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
789 final boolean before) {
790 rWTransaction.delete(datastore, path.getParent().getParent());
791 final InstanceIdentifierContext<?> instanceIdentifier =
792 ControllerContext.getInstance().toInstanceIdentifier(point);
794 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
795 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
804 final NormalizedNode<?, ?> emptySubtree =
805 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
806 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
807 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
809 checkItemDoesNotExists(rWTransaction, datastore, path);
810 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
812 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
813 checkItemDoesNotExists(rWTransaction, datastore, childPath);
814 rWTransaction.put(datastore, childPath, nodeChild);
819 private void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
820 final LogicalDatastoreType datastore,
821 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
822 final String point, final MapNode readList, final boolean before) {
823 rWTransaction.delete(datastore, path.getParent().getParent());
824 final InstanceIdentifierContext<?> instanceIdentifier =
825 ControllerContext.getInstance().toInstanceIdentifier(point);
827 for (final MapEntryNode mapEntryNode : readList.getValue()) {
828 if (mapEntryNode.getIdentifier()
829 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
838 final NormalizedNode<?, ?> emptySubtree =
839 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
840 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
841 for (final MapEntryNode mapEntryNode : readList.getValue()) {
843 checkItemDoesNotExists(rWTransaction, datastore, path);
844 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
846 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
847 checkItemDoesNotExists(rWTransaction, datastore, childPath);
848 rWTransaction.put(datastore, childPath, mapEntryNode);
853 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
854 final YangInstanceIdentifier parent = path.getParent();
855 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
856 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
858 if (dataSchemaNode instanceof ListSchemaNode) {
859 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
860 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
862 return dataSchemaNode;
864 if (dataSchemaNode instanceof LeafListSchemaNode) {
865 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
866 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
868 return dataSchemaNode;
870 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
873 private void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
874 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
875 if (payload instanceof MapNode) {
876 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
877 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
878 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
879 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
880 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
881 checkItemDoesNotExists(rWTransaction, datastore, childPath);
882 rWTransaction.put(datastore, childPath, child);
884 } else if (payload instanceof LeafSetNode) {
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 LeafSetEntryNode<?> child : ((LeafSetNode<?>) payload).getValue()) {
889 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
890 checkItemDoesNotExists(rWTransaction, datastore, childPath);
891 rWTransaction.put(datastore, childPath, child);
894 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
898 private static void simplePostPut(final DOMDataReadWriteTransaction rWTransaction,
899 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
900 final SchemaContext schemaContext) {
901 checkItemDoesNotExists(rWTransaction, datastore, path);
902 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
903 rWTransaction.put(datastore, path, payload);
906 private static boolean doesItemExist(final DOMDataReadWriteTransaction rWTransaction,
907 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
909 return rWTransaction.exists(store, path).checkedGet();
910 } catch (ReadFailedException e) {
911 rWTransaction.cancel();
912 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
913 e, e.getErrorList());
918 * Check if item already exists. Throws error if it does NOT already exist.
919 * @param rWTransaction Current transaction
920 * @param store Used datastore
921 * @param path Path to item to verify its existence
923 private static void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
924 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
925 if (!doesItemExist(rWTransaction, store, path)) {
926 final String errMsg = "Operation via Restconf was not executed because data does not exist";
927 LOG.trace("{}:{}", errMsg, path);
928 rWTransaction.cancel();
929 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
930 ErrorTag.DATA_MISSING);
935 * Check if item does NOT already exist. Throws error if it already exists.
936 * @param rWTransaction Current transaction
937 * @param store Used datastore
938 * @param path Path to item to verify its existence
940 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
941 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
942 if (doesItemExist(rWTransaction, store, path)) {
943 final String errMsg = "Operation via Restconf was not executed because data already exists";
944 LOG.trace("{}:{}", errMsg, path);
945 rWTransaction.cancel();
946 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
947 ErrorTag.DATA_EXISTS);
952 * PUT data and submit {@link DOMDataReadWriteTransaction}
957 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
958 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
959 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
960 final String insert, final String point) {
961 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
962 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
963 return readWriteTransaction.submit();
967 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
972 private void putDataWithinTransaction(
973 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
974 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
975 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
976 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
979 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
980 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
981 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
982 final String insert, final String point) {
983 if (insert == null) {
984 makePut(rWTransaction, datastore, path, payload, schemaContext);
986 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
987 checkItemDoesNotExists(rWTransaction, datastore, path);
990 if (schemaNode instanceof ListSchemaNode) {
991 final OrderedMapNode readList =
992 (OrderedMapNode) this.readConfigurationData(path.getParent());
993 if (readList == null || readList.getValue().isEmpty()) {
994 simplePut(datastore, path, rWTransaction, schemaContext, payload);
996 rWTransaction.delete(datastore, path.getParent());
997 simplePut(datastore, path, rWTransaction, schemaContext, payload);
998 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
1001 final OrderedLeafSetNode<?> readLeafList =
1002 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1003 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1004 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1006 rWTransaction.delete(datastore, path.getParent());
1007 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1008 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1014 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1017 if (schemaNode instanceof ListSchemaNode) {
1018 final OrderedMapNode readList =
1019 (OrderedMapNode) this.readConfigurationData(path.getParent());
1020 if (readList == null || readList.getValue().isEmpty()) {
1021 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1023 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1027 final OrderedLeafSetNode<?> readLeafList =
1028 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1029 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1030 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1032 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1033 readLeafList, true);
1038 if (schemaNode instanceof ListSchemaNode) {
1039 final OrderedMapNode readList =
1040 (OrderedMapNode) this.readConfigurationData(path.getParent());
1041 if (readList == null || readList.getValue().isEmpty()) {
1042 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1044 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1048 final OrderedLeafSetNode<?> readLeafList =
1049 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1050 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1051 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1053 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1054 readLeafList, false);
1059 throw new RestconfDocumentedException(
1060 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1061 + "but was: " + insert);
1066 private void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1067 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1068 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1069 final boolean before) {
1070 rWTransaction.delete(datastore, path.getParent());
1071 final InstanceIdentifierContext<?> instanceIdentifier =
1072 ControllerContext.getInstance().toInstanceIdentifier(point);
1074 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1075 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1084 final NormalizedNode<?, ?> emptySubtree =
1085 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1086 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1087 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1089 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1091 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1092 rWTransaction.put(datastore, childPath, nodeChild);
1097 private void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1098 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1099 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1100 final boolean before) {
1101 rWTransaction.delete(datastore, path.getParent());
1102 final InstanceIdentifierContext<?> instanceIdentifier =
1103 ControllerContext.getInstance().toInstanceIdentifier(point);
1105 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1106 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1115 final NormalizedNode<?, ?> emptySubtree =
1116 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1117 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1118 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1120 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1122 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1123 rWTransaction.put(datastore, childPath, mapEntryNode);
1128 private static void makePut(final DOMDataReadWriteTransaction writeTransaction,
1129 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1130 final SchemaContext schemaContext) {
1131 if (payload instanceof MapNode) {
1132 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1133 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1134 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1135 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1136 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1137 writeTransaction.put(datastore, childPath, child);
1140 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1144 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1145 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1146 final NormalizedNode<?, ?> payload) {
1147 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1148 writeTransaction.put(datastore, path, payload);
1151 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1152 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1153 final YangInstanceIdentifier path) {
1154 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1155 checkItemExists(readWriteTransaction, datastore, path);
1156 readWriteTransaction.delete(datastore, path);
1157 return readWriteTransaction.submit();
1160 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction writeTransaction,
1161 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1162 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1163 writeTransaction.delete(datastore, path);
1166 private static void mergeDataWithinTransaction(
1167 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1168 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1169 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1170 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1172 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1173 // OpenDaylight should not change it.
1174 writeTransaction.merge(datastore, path, payload);
1177 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1178 this.domDataBroker = domDataBroker;
1181 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1182 checkPreconditions();
1184 if (listener.isListening()) {
1188 final SchemaPath path = listener.getSchemaPath();
1189 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1190 .registerNotificationListener(listener, path);
1192 listener.setRegistration(registration);
1195 private final class PATCHStatusContextHelper {
1196 PATCHStatusContext status;
1198 public PATCHStatusContext getStatus() {
1202 public void setStatus(final PATCHStatusContext status) {
1203 this.status = status;
1207 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1208 final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx,
1209 final SchemaContext schemaContext) {
1210 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1211 YangInstanceIdentifier rootNormalizedPath = null;
1213 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1215 while (it.hasNext()) {
1216 final PathArgument pathArgument = it.next();
1217 if (rootNormalizedPath == null) {
1218 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1222 normalizedPathWithoutChildArgs.add(pathArgument);
1226 if (normalizedPathWithoutChildArgs.isEmpty()) {
1230 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1232 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1233 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1234 rwTx.merge(store, rootNormalizedPath, parentStructure);