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.DOMDataReadOnlyTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
37 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
38 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
42 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
43 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
44 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
45 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
46 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
47 import org.opendaylight.yangtools.concepts.ListenerRegistration;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.common.RpcError;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
54 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
56 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
64 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
65 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
66 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
67 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
68 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
69 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
70 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
71 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
77 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
81 public class BrokerFacade {
82 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
84 private final static BrokerFacade INSTANCE = new BrokerFacade();
85 private volatile DOMRpcService rpcService;
86 private volatile ConsumerSession context;
87 private DOMDataBroker domDataBroker;
88 private DOMNotificationService domNotification;
90 private BrokerFacade() {}
92 public void setRpcService(final DOMRpcService router) {
93 this.rpcService = router;
96 public void setDomNotificationService(final DOMNotificationService domNotification) {
97 this.domNotification = domNotification;
100 public void setContext(final ConsumerSession context) {
101 this.context = context;
104 public static BrokerFacade getInstance() {
105 return BrokerFacade.INSTANCE;
108 private void checkPreconditions() {
109 if (this.context == null || this.domDataBroker == null) {
110 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
115 * Read config data by path
121 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
122 return readConfigurationData(path, null);
126 * Read config data by path
131 * - value of with-defaults parameter
134 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
135 checkPreconditions();
136 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
137 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
142 * Read config data from mount point by path.
145 * - mount point for reading data
150 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
151 final YangInstanceIdentifier path) {
152 return readConfigurationData(mountPoint, path, null);
156 * Read config data from mount point by path.
159 * - mount point for reading data
163 * - value of with-defaults parameter
166 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
167 final String withDefa) {
168 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
169 if (domDataBrokerService.isPresent()) {
170 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
171 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
174 final String errMsg = "DOM data broker service isn't available for mount point " + path;
176 throw new RestconfDocumentedException(errMsg);
180 * Read operational data by path.
186 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
187 checkPreconditions();
189 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
190 return readDataViaTransaction(tx, OPERATIONAL, path);
195 * Read operational data from mount point by path.
198 * - mount point for reading data
203 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
204 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
205 if (domDataBrokerService.isPresent()) {
206 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
207 return readDataViaTransaction(tx, OPERATIONAL, path);
210 final String errMsg = "DOM data broker service isn't available for mount point " + path;
212 throw new RestconfDocumentedException(errMsg);
216 * <b>PUT configuration data</b>
218 * Prepare result(status) for PUT operation and PUT data via transaction.
219 * Return wrapped status and future from PUT.
221 * @param globalSchema
222 * - used by merge parents (if contains list)
229 * @return wrapper of status and future of PUT
231 public PutResult commitConfigurationDataPut(
232 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
233 final String insert, final String point) {
234 Preconditions.checkNotNull(globalSchema);
235 Preconditions.checkNotNull(path);
236 Preconditions.checkNotNull(payload);
238 checkPreconditions();
240 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
241 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
243 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
244 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
245 return new PutResult(status, future);
249 * <b>PUT configuration data (Mount point)</b>
251 * Prepare result(status) for PUT operation and PUT data via transaction.
252 * Return wrapped status and future from PUT.
255 * - mount point for getting transaction for operation and schema
256 * context for merging parents(if contains list)
263 * @return wrapper of status and future of PUT
265 public PutResult commitMountPointDataPut(
266 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
267 final String insert, final String point) {
268 Preconditions.checkNotNull(mountPoint);
269 Preconditions.checkNotNull(path);
270 Preconditions.checkNotNull(payload);
272 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
273 if (domDataBrokerService.isPresent()) {
274 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
275 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
276 ? Status.OK : Status.CREATED;
277 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
278 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
280 return new PutResult(status, future);
282 final String errMsg = "DOM data broker service isn't available for mount point " + path;
284 throw new RestconfDocumentedException(errMsg);
287 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
288 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
290 // get new transaction and schema context on server or on mounted device
291 final SchemaContext schemaContext;
292 final DOMDataReadWriteTransaction patchTransaction;
293 if (mountPoint == null) {
294 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
295 patchTransaction = this.domDataBroker.newReadWriteTransaction();
297 schemaContext = mountPoint.getSchemaContext();
299 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
301 if (optional.isPresent()) {
302 patchTransaction = optional.get().newReadWriteTransaction();
304 // if mount point does not have broker it is not possible to continue and global error is reported
305 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
306 patchContext.getPatchId(), mountPoint.getIdentifier());
307 return new PATCHStatusContext(
308 patchContext.getPatchId(),
311 ImmutableList.of(new RestconfError(
312 ErrorType.APPLICATION,
313 ErrorTag.OPERATION_FAILED,
314 "DOM data broker service isn't available for mount point "
315 + mountPoint.getIdentifier()))
320 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
321 List<RestconfError> editErrors;
322 boolean withoutError = true;
324 for (final PATCHEntity patchEntity : patchContext.getData()) {
325 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
331 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
332 patchEntity.getNode(), schemaContext);
333 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
334 } catch (final RestconfDocumentedException e) {
335 LOG.error("Error call http PATCH operation {} on target {}",
337 patchEntity.getTargetNode().toString());
339 editErrors = new ArrayList<>();
340 editErrors.addAll(e.getErrors());
341 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
342 withoutError = false;
349 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
350 .getTargetNode(), patchEntity.getNode(), schemaContext);
351 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
352 } catch (final RestconfDocumentedException e) {
353 LOG.error("Error call http PATCH operation {} on target {}",
355 patchEntity.getTargetNode().toString());
357 editErrors = new ArrayList<>();
358 editErrors.addAll(e.getErrors());
359 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
360 withoutError = false;
367 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
369 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
370 } catch (final RestconfDocumentedException e) {
371 LOG.error("Error call http PATCH operation {} on target {}",
373 patchEntity.getTargetNode().toString());
375 editErrors = new ArrayList<>();
376 editErrors.addAll(e.getErrors());
377 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
378 withoutError = false;
385 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
387 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
388 } catch (final RestconfDocumentedException e) {
389 LOG.error("Error call http PATCH operation {} on target {}",
391 patchEntity.getTargetNode().toString());
393 editErrors = new ArrayList<>();
394 editErrors.addAll(e.getErrors());
395 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
396 withoutError = false;
403 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
404 patchEntity.getNode(), schemaContext);
405 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
406 } catch (final RestconfDocumentedException e) {
407 LOG.error("Error call http PATCH operation {} on target {}",
409 patchEntity.getTargetNode().toString());
411 editErrors = new ArrayList<>();
412 editErrors.addAll(e.getErrors());
413 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
414 withoutError = false;
419 LOG.error("Unsupported http PATCH operation {} on target {}",
421 patchEntity.getTargetNode().toString());
426 // if errors then cancel transaction and return error status
428 patchTransaction.cancel();
429 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
432 // if no errors commit transaction
433 final CountDownLatch waiter = new CountDownLatch(1);
434 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
435 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
437 Futures.addCallback(future, new FutureCallback<Void>() {
439 public void onSuccess(@Nullable final Void result) {
440 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
446 public void onFailure(final Throwable t) {
447 // if commit failed it is global error
448 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
449 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
450 false, ImmutableList.of(
451 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
457 return status.getStatus();
460 // POST configuration
461 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
462 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
463 final String insert, final String point) {
464 checkPreconditions();
465 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
466 globalSchema, insert, point);
469 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
470 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
471 final String insert, final String point) {
472 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
473 if (domDataBrokerService.isPresent()) {
474 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
475 payload, mountPoint.getSchemaContext(), insert, point);
477 final String errMsg = "DOM data broker service isn't available for mount point " + path;
479 throw new RestconfDocumentedException(errMsg);
482 // DELETE configuration
483 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
484 final YangInstanceIdentifier path) {
485 checkPreconditions();
486 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
489 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
490 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
491 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
492 if (domDataBrokerService.isPresent()) {
493 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
495 final String errMsg = "DOM data broker service isn't available for mount point " + path;
497 throw new RestconfDocumentedException(errMsg);
501 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
502 checkPreconditions();
503 if (this.rpcService == null) {
504 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
506 LOG.trace("Invoke RPC {} with input: {}", type, input);
507 return this.rpcService.invokeRpc(type, input);
510 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
511 final ListenerAdapter listener) {
512 checkPreconditions();
514 if (listener.isListening()) {
518 final YangInstanceIdentifier path = listener.getPath();
519 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
520 datastore, path, listener, scope);
522 listener.setRegistration(registration);
525 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
526 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
527 return readDataViaTransaction(transaction, datastore, path, null);
530 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
531 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
532 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
535 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
536 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
537 prepareDataByParamWithDef(optional.get(), path, withDefa);
538 } catch (ReadFailedException e) {
539 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
540 for (final RpcError error : e.getErrorList()) {
541 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
542 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
543 throw new RestconfDocumentedException(
546 ErrorTag.RESOURCE_DENIED_TRANSPORT);
549 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
553 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
554 final YangInstanceIdentifier path, final String withDefa) {
564 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
567 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
568 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
569 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
570 if (result instanceof ContainerNode) {
571 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
572 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
573 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
574 return builder.build();
577 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
578 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
579 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
580 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
581 return builder.build();
584 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
585 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
586 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
587 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
588 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
589 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
590 if (child instanceof ContainerNode) {
591 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
592 Builders.containerBuilder((ContainerSchemaNode) childSchema);
593 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
594 builder.withChild(childBuilder.build());
595 } else if (child instanceof MapNode) {
596 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
597 Builders.mapBuilder((ListSchemaNode) childSchema);
598 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
599 ((ListSchemaNode) childSchema).getKeyDefinition());
600 builder.withChild(childBuilder.build());
601 } else if (child instanceof LeafNode) {
602 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
603 final String nodeVal = ((LeafNode<String>) child).getValue();
604 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
605 Builders.leafBuilder((LeafSchemaNode) childSchema);
606 if (keys.contains(child.getNodeType())) {
607 leafBuilder.withValue(((LeafNode) child).getValue());
608 builder.withChild(leafBuilder.build());
611 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
612 leafBuilder.withValue(((LeafNode) child).getValue());
613 builder.withChild(leafBuilder.build());
616 if (defaultVal != null && defaultVal.equals(nodeVal)) {
617 leafBuilder.withValue(((LeafNode) child).getValue());
618 builder.withChild(leafBuilder.build());
626 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
627 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
628 final List<QName> keys) {
629 for (final MapEntryNode mapEntryNode : result.getValue()) {
630 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
631 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
632 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
633 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
634 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
635 builder.withChild(mapEntryBuilder.build());
639 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
640 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
641 final YangInstanceIdentifier actualPath, final boolean trim) {
642 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
643 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
644 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
645 if(child instanceof ContainerNode){
646 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
647 Builders.containerBuilder((ContainerSchemaNode) childSchema);
648 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
649 builder.withChild(builderChild.build());
650 } else if (child instanceof MapNode) {
651 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
652 Builders.mapBuilder((ListSchemaNode) childSchema);
653 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
654 ((ListSchemaNode) childSchema).getKeyDefinition());
655 builder.withChild(childBuilder.build());
656 } else if (child instanceof LeafNode) {
657 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
658 final String nodeVal = ((LeafNode<String>) child).getValue();
659 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
660 Builders.leafBuilder((LeafSchemaNode) childSchema);
662 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
663 leafBuilder.withValue(((LeafNode) child).getValue());
664 builder.withChild(leafBuilder.build());
667 if (defaultVal != null && defaultVal.equals(nodeVal)) {
668 leafBuilder.withValue(((LeafNode) child).getValue());
669 builder.withChild(leafBuilder.build());
677 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
679 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
680 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
681 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
682 final String insert, final String point) {
683 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
684 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
685 return rWTransaction.submit();
689 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
691 private void postDataWithinTransaction(
692 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
693 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
694 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
695 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
698 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
699 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
700 final SchemaContext schemaContext, final String insert, final String point) {
701 if (insert == null) {
702 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
706 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
707 checkItemDoesNotExists(rWTransaction, datastore, path);
710 if(schemaNode instanceof ListSchemaNode){
711 final OrderedMapNode readList =
712 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
713 if (readList == null || readList.getValue().isEmpty()) {
714 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
716 rWTransaction.delete(datastore, path.getParent().getParent());
717 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
718 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
722 final OrderedLeafSetNode<?> readLeafList =
723 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
724 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
725 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
727 rWTransaction.delete(datastore, path.getParent());
728 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
729 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
735 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
738 if(schemaNode instanceof ListSchemaNode){
739 final OrderedMapNode readList =
740 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
741 if (readList == null || readList.getValue().isEmpty()) {
742 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
744 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
749 final OrderedLeafSetNode<?> readLeafList =
750 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
751 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
752 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
754 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
760 if (schemaNode instanceof ListSchemaNode) {
761 final OrderedMapNode readList =
762 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
763 if (readList == null || readList.getValue().isEmpty()) {
764 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
766 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
771 final OrderedLeafSetNode<?> readLeafList =
772 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
773 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
774 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
776 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
777 readLeafList, false);
782 throw new RestconfDocumentedException(
783 "Used bad value of insert parameter. Possible values are first, last, before or after, "
784 + "but was: " + insert);
788 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
789 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
790 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
791 final boolean before) {
792 rWTransaction.delete(datastore, path.getParent().getParent());
793 final InstanceIdentifierContext<?> instanceIdentifier =
794 ControllerContext.getInstance().toInstanceIdentifier(point);
796 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
797 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
806 final NormalizedNode<?, ?> emptySubtree =
807 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
808 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
809 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
811 checkItemDoesNotExists(rWTransaction, datastore, path);
812 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
814 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
815 checkItemDoesNotExists(rWTransaction, datastore, childPath);
816 rWTransaction.put(datastore, childPath, nodeChild);
821 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
822 final LogicalDatastoreType datastore,
823 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
824 final String point, final MapNode readList, final boolean before) {
825 rWTransaction.delete(datastore, path.getParent().getParent());
826 final InstanceIdentifierContext<?> instanceIdentifier =
827 ControllerContext.getInstance().toInstanceIdentifier(point);
829 for (final MapEntryNode mapEntryNode : readList.getValue()) {
830 if (mapEntryNode.getIdentifier()
831 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
840 final NormalizedNode<?, ?> emptySubtree =
841 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
842 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
843 for (final MapEntryNode mapEntryNode : readList.getValue()) {
845 checkItemDoesNotExists(rWTransaction, datastore, path);
846 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
848 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
849 checkItemDoesNotExists(rWTransaction, datastore, childPath);
850 rWTransaction.put(datastore, childPath, mapEntryNode);
855 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
856 final YangInstanceIdentifier parent = path.getParent();
857 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
858 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
860 if (dataSchemaNode instanceof ListSchemaNode) {
861 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
862 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
864 return dataSchemaNode;
866 if (dataSchemaNode instanceof LeafListSchemaNode) {
867 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
868 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
870 return dataSchemaNode;
872 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
875 private static void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction,
876 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
877 final SchemaContext schemaContext) {
878 final Collection<? extends NormalizedNode<?, ?>> children;
879 if (payload instanceof MapNode) {
880 children = ((MapNode) payload).getValue();
881 } else if (payload instanceof LeafSetNode) {
882 children = ((LeafSetNode<?>) payload).getValue();
884 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
888 // We are putting multiple children, we really need a create() operation, but until we have that we make do
889 // with a two-step process of verifying if the children exist and then putting them in.
890 for (final NormalizedNode<?, ?> child : children) {
891 checkItemDoesNotExists(rWTransaction, datastore, path.node(child.getIdentifier()));
894 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
895 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
896 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
897 for (final NormalizedNode<?, ?> child : children) {
898 rWTransaction.put(datastore, path.node(child.getIdentifier()), child);
902 private static void simplePostPut(final DOMDataReadWriteTransaction rWTransaction,
903 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
904 final SchemaContext schemaContext) {
905 checkItemDoesNotExists(rWTransaction, datastore, path);
906 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
907 rWTransaction.put(datastore, path, payload);
910 private static boolean doesItemExist(final DOMDataReadWriteTransaction rWTransaction,
911 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
913 return rWTransaction.exists(store, path).checkedGet();
914 } catch (ReadFailedException e) {
915 rWTransaction.cancel();
916 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
917 e, e.getErrorList());
922 * Check if item already exists. Throws error if it does NOT already exist.
923 * @param rWTransaction Current transaction
924 * @param store Used datastore
925 * @param path Path to item to verify its existence
927 private static void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
928 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
929 if (!doesItemExist(rWTransaction, store, path)) {
930 final String errMsg = "Operation via Restconf was not executed because data does not exist";
931 LOG.trace("{}:{}", errMsg, path);
932 rWTransaction.cancel();
933 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
934 ErrorTag.DATA_MISSING);
939 * Check if item does NOT already exist. Throws error if it already exists.
940 * @param rWTransaction Current transaction
941 * @param store Used datastore
942 * @param path Path to item to verify its existence
944 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
945 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
946 if (doesItemExist(rWTransaction, store, path)) {
947 final String errMsg = "Operation via Restconf was not executed because data already exists";
948 LOG.trace("{}:{}", errMsg, path);
949 rWTransaction.cancel();
950 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
951 ErrorTag.DATA_EXISTS);
956 * PUT data and submit {@link DOMDataReadWriteTransaction}
961 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
962 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
963 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
964 final String insert, final String point) {
965 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
966 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
967 return readWriteTransaction.submit();
971 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
976 private void putDataWithinTransaction(
977 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
978 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
979 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
980 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
983 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
984 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
985 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
986 final String insert, final String point) {
987 if (insert == null) {
988 makePut(rWTransaction, datastore, path, payload, schemaContext);
990 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
991 checkItemDoesNotExists(rWTransaction, datastore, path);
994 if (schemaNode instanceof ListSchemaNode) {
995 final OrderedMapNode readList =
996 (OrderedMapNode) this.readConfigurationData(path.getParent());
997 if (readList == null || readList.getValue().isEmpty()) {
998 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1000 rWTransaction.delete(datastore, path.getParent());
1001 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1002 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
1005 final OrderedLeafSetNode<?> readLeafList =
1006 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1007 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1008 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1010 rWTransaction.delete(datastore, path.getParent());
1011 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1012 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1018 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1021 if (schemaNode instanceof ListSchemaNode) {
1022 final OrderedMapNode readList =
1023 (OrderedMapNode) this.readConfigurationData(path.getParent());
1024 if (readList == null || readList.getValue().isEmpty()) {
1025 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1027 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1031 final OrderedLeafSetNode<?> readLeafList =
1032 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1033 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1034 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1036 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1037 readLeafList, true);
1042 if (schemaNode instanceof ListSchemaNode) {
1043 final OrderedMapNode readList =
1044 (OrderedMapNode) this.readConfigurationData(path.getParent());
1045 if (readList == null || readList.getValue().isEmpty()) {
1046 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1048 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1052 final OrderedLeafSetNode<?> readLeafList =
1053 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1054 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1055 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1057 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1058 readLeafList, false);
1063 throw new RestconfDocumentedException(
1064 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1065 + "but was: " + insert);
1070 private static void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1071 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1072 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1073 final boolean before) {
1074 rWTransaction.delete(datastore, path.getParent());
1075 final InstanceIdentifierContext<?> instanceIdentifier =
1076 ControllerContext.getInstance().toInstanceIdentifier(point);
1078 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1079 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1088 final NormalizedNode<?, ?> emptySubtree =
1089 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1090 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1091 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1093 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1095 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1096 rWTransaction.put(datastore, childPath, nodeChild);
1101 private static void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1102 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1103 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1104 final boolean before) {
1105 rWTransaction.delete(datastore, path.getParent());
1106 final InstanceIdentifierContext<?> instanceIdentifier =
1107 ControllerContext.getInstance().toInstanceIdentifier(point);
1109 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1110 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1119 final NormalizedNode<?, ?> emptySubtree =
1120 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1121 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1122 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1124 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1126 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1127 rWTransaction.put(datastore, childPath, mapEntryNode);
1132 private static void makePut(final DOMDataReadWriteTransaction writeTransaction,
1133 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1134 final SchemaContext schemaContext) {
1135 if (payload instanceof MapNode) {
1136 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1137 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1138 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1139 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1140 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1141 writeTransaction.put(datastore, childPath, child);
1144 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1148 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1149 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1150 final NormalizedNode<?, ?> payload) {
1151 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1152 writeTransaction.put(datastore, path, payload);
1155 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1156 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1157 final YangInstanceIdentifier path) {
1158 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1159 checkItemExists(readWriteTransaction, datastore, path);
1160 readWriteTransaction.delete(datastore, path);
1161 return readWriteTransaction.submit();
1164 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction writeTransaction,
1165 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1166 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1167 writeTransaction.delete(datastore, path);
1170 private static void mergeDataWithinTransaction(
1171 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1172 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1173 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1174 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1176 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1177 // OpenDaylight should not change it.
1178 writeTransaction.merge(datastore, path, payload);
1181 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1182 this.domDataBroker = domDataBroker;
1185 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1186 checkPreconditions();
1188 if (listener.isListening()) {
1192 final SchemaPath path = listener.getSchemaPath();
1193 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1194 .registerNotificationListener(listener, path);
1196 listener.setRegistration(registration);
1199 private final class PATCHStatusContextHelper {
1200 PATCHStatusContext status;
1202 public PATCHStatusContext getStatus() {
1206 public void setStatus(final PATCHStatusContext status) {
1207 this.status = status;
1211 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1212 final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx,
1213 final SchemaContext schemaContext) {
1214 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1215 YangInstanceIdentifier rootNormalizedPath = null;
1217 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1219 while (it.hasNext()) {
1220 final PathArgument pathArgument = it.next();
1221 if (rootNormalizedPath == null) {
1222 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1226 normalizedPathWithoutChildArgs.add(pathArgument);
1230 if (normalizedPathWithoutChildArgs.isEmpty()) {
1234 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1236 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1237 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1238 rwTx.merge(store, rootNormalizedPath, parentStructure);