2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.sal.restconf.impl;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map.Entry;
24 import java.util.concurrent.CountDownLatch;
25 import javax.annotation.Nullable;
26 import javax.ws.rs.core.Response.Status;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
38 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
39 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
43 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
44 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
45 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
46 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
47 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
48 import org.opendaylight.yangtools.concepts.ListenerRegistration;
49 import org.opendaylight.yangtools.yang.common.QName;
50 import org.opendaylight.yangtools.yang.common.RpcError;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
55 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
57 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
65 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
66 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
67 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
68 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
69 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
70 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
71 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
72 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
75 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
78 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
82 public class BrokerFacade {
83 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
85 private final static BrokerFacade INSTANCE = new BrokerFacade();
86 private volatile DOMRpcService rpcService;
87 private volatile ConsumerSession context;
88 private DOMDataBroker domDataBroker;
89 private DOMNotificationService domNotification;
91 private BrokerFacade() {}
93 public void setRpcService(final DOMRpcService router) {
94 this.rpcService = router;
97 public void setDomNotificationService(final DOMNotificationService domNotification) {
98 this.domNotification = domNotification;
101 public void setContext(final ConsumerSession context) {
102 this.context = context;
105 public static BrokerFacade getInstance() {
106 return BrokerFacade.INSTANCE;
109 private void checkPreconditions() {
110 if (this.context == null || this.domDataBroker == null) {
111 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
116 * Read config data by path
122 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
123 return readConfigurationData(path, null);
127 * Read config data by path
132 * - value of with-defaults parameter
135 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
136 checkPreconditions();
137 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
138 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
143 * Read config data from mount point by path.
146 * - mount point for reading data
151 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
152 final YangInstanceIdentifier path) {
153 return readConfigurationData(mountPoint, path, null);
157 * Read config data from mount point by path.
160 * - mount point for reading data
164 * - value of with-defaults parameter
167 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
168 final String withDefa) {
169 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
170 if (domDataBrokerService.isPresent()) {
171 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
172 return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
175 final String errMsg = "DOM data broker service isn't available for mount point " + path;
177 throw new RestconfDocumentedException(errMsg);
181 * Read operational data by path.
187 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
188 checkPreconditions();
190 try (DOMDataReadOnlyTransaction tx = this.domDataBroker.newReadOnlyTransaction()) {
191 return readDataViaTransaction(tx, OPERATIONAL, path);
196 * Read operational data from mount point by path.
199 * - mount point for reading data
204 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
205 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
206 if (domDataBrokerService.isPresent()) {
207 try (DOMDataReadOnlyTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
208 return readDataViaTransaction(tx, OPERATIONAL, path);
211 final String errMsg = "DOM data broker service isn't available for mount point " + path;
213 throw new RestconfDocumentedException(errMsg);
217 * <b>PUT configuration data</b>
219 * Prepare result(status) for PUT operation and PUT data via transaction.
220 * Return wrapped status and future from PUT.
222 * @param globalSchema
223 * - used by merge parents (if contains list)
230 * @return wrapper of status and future of PUT
232 public PutResult commitConfigurationDataPut(
233 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
234 final String insert, final String point) {
235 Preconditions.checkNotNull(globalSchema);
236 Preconditions.checkNotNull(path);
237 Preconditions.checkNotNull(payload);
239 checkPreconditions();
241 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
242 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
244 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
245 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
246 return new PutResult(status, future);
250 * <b>PUT configuration data (Mount point)</b>
252 * Prepare result(status) for PUT operation and PUT data via transaction.
253 * Return wrapped status and future from PUT.
256 * - mount point for getting transaction for operation and schema
257 * context for merging parents(if contains list)
264 * @return wrapper of status and future of PUT
266 public PutResult commitMountPointDataPut(
267 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
268 final String insert, final String point) {
269 Preconditions.checkNotNull(mountPoint);
270 Preconditions.checkNotNull(path);
271 Preconditions.checkNotNull(payload);
273 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
274 if (domDataBrokerService.isPresent()) {
275 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
276 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
277 ? Status.OK : Status.CREATED;
278 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
279 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
281 return new PutResult(status, future);
283 final String errMsg = "DOM data broker service isn't available for mount point " + path;
285 throw new RestconfDocumentedException(errMsg);
288 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
289 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
291 // get new transaction and schema context on server or on mounted device
292 final SchemaContext schemaContext;
293 final DOMDataReadWriteTransaction patchTransaction;
294 if (mountPoint == null) {
295 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
296 patchTransaction = this.domDataBroker.newReadWriteTransaction();
298 schemaContext = mountPoint.getSchemaContext();
300 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
302 if (optional.isPresent()) {
303 patchTransaction = optional.get().newReadWriteTransaction();
305 // if mount point does not have broker it is not possible to continue and global error is reported
306 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
307 patchContext.getPatchId(), mountPoint.getIdentifier());
308 return new PATCHStatusContext(
309 patchContext.getPatchId(),
312 ImmutableList.of(new RestconfError(
313 ErrorType.APPLICATION,
314 ErrorTag.OPERATION_FAILED,
315 "DOM data broker service isn't available for mount point "
316 + mountPoint.getIdentifier()))
321 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
322 List<RestconfError> editErrors;
323 boolean withoutError = true;
325 for (final PATCHEntity patchEntity : patchContext.getData()) {
326 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
332 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
333 patchEntity.getNode(), schemaContext);
334 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
335 } catch (final RestconfDocumentedException e) {
336 LOG.error("Error call http PATCH operation {} on target {}",
338 patchEntity.getTargetNode().toString());
340 editErrors = new ArrayList<>();
341 editErrors.addAll(e.getErrors());
342 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
343 withoutError = false;
350 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
351 .getTargetNode(), patchEntity.getNode(), schemaContext);
352 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
353 } catch (final RestconfDocumentedException e) {
354 LOG.error("Error call http PATCH operation {} on target {}",
356 patchEntity.getTargetNode().toString());
358 editErrors = new ArrayList<>();
359 editErrors.addAll(e.getErrors());
360 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
361 withoutError = false;
368 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
370 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
371 } catch (final RestconfDocumentedException e) {
372 LOG.error("Error call http PATCH operation {} on target {}",
374 patchEntity.getTargetNode().toString());
376 editErrors = new ArrayList<>();
377 editErrors.addAll(e.getErrors());
378 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
379 withoutError = false;
386 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
388 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
389 } catch (final RestconfDocumentedException e) {
390 LOG.error("Error call http PATCH operation {} on target {}",
392 patchEntity.getTargetNode().toString());
394 editErrors = new ArrayList<>();
395 editErrors.addAll(e.getErrors());
396 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
397 withoutError = false;
404 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
405 patchEntity.getNode(), schemaContext);
406 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
407 } catch (final RestconfDocumentedException e) {
408 LOG.error("Error call http PATCH operation {} on target {}",
410 patchEntity.getTargetNode().toString());
412 editErrors = new ArrayList<>();
413 editErrors.addAll(e.getErrors());
414 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
415 withoutError = false;
420 LOG.error("Unsupported http PATCH operation {} on target {}",
422 patchEntity.getTargetNode().toString());
427 // if errors then cancel transaction and return error status
429 patchTransaction.cancel();
430 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
433 // if no errors commit transaction
434 final CountDownLatch waiter = new CountDownLatch(1);
435 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
436 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
438 Futures.addCallback(future, new FutureCallback<Void>() {
440 public void onSuccess(@Nullable final Void result) {
441 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
447 public void onFailure(final Throwable t) {
448 // if commit failed it is global error
449 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
450 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
451 false, ImmutableList.of(
452 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
458 return status.getStatus();
461 // POST configuration
462 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
463 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
464 final String insert, final String point) {
465 checkPreconditions();
466 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
467 globalSchema, insert, point);
470 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
471 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
472 final String insert, final String point) {
473 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
474 if (domDataBrokerService.isPresent()) {
475 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
476 payload, mountPoint.getSchemaContext(), insert, point);
478 final String errMsg = "DOM data broker service isn't available for mount point " + path;
480 throw new RestconfDocumentedException(errMsg);
483 // DELETE configuration
484 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
485 final YangInstanceIdentifier path) {
486 checkPreconditions();
487 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
490 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
491 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
492 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
493 if (domDataBrokerService.isPresent()) {
494 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
496 final String errMsg = "DOM data broker service isn't available for mount point " + path;
498 throw new RestconfDocumentedException(errMsg);
502 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
503 checkPreconditions();
504 if (this.rpcService == null) {
505 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
507 LOG.trace("Invoke RPC {} with input: {}", type, input);
508 return this.rpcService.invokeRpc(type, input);
511 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
512 final ListenerAdapter listener) {
513 checkPreconditions();
515 if (listener.isListening()) {
519 final YangInstanceIdentifier path = listener.getPath();
520 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
521 datastore, path, listener, scope);
523 listener.setRegistration(registration);
526 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
527 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
528 return readDataViaTransaction(transaction, datastore, path, null);
531 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
532 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
533 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
536 final Optional<NormalizedNode<?, ?>> optional = transaction.read(datastore, path).checkedGet();
537 return !optional.isPresent() ? null : withDefa == null ? optional.get() :
538 prepareDataByParamWithDef(optional.get(), path, withDefa);
539 } catch (ReadFailedException e) {
540 LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
541 for (final RpcError error : e.getErrorList()) {
542 if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
543 && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
544 throw new RestconfDocumentedException(
547 ErrorTag.RESOURCE_DENIED_TRANSPORT);
550 throw new RestconfDocumentedException("Error reading data.", e, e.getErrorList());
554 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
555 final YangInstanceIdentifier path, final String withDefa) {
565 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
568 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
569 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
570 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
571 if (result instanceof ContainerNode) {
572 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
573 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
574 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
575 return builder.build();
578 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
579 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
580 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
581 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
582 return builder.build();
585 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
586 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
587 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
588 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
589 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
590 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
591 if (child instanceof ContainerNode) {
592 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
593 Builders.containerBuilder((ContainerSchemaNode) childSchema);
594 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
595 builder.withChild(childBuilder.build());
596 } else if (child instanceof MapNode) {
597 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
598 Builders.mapBuilder((ListSchemaNode) childSchema);
599 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
600 ((ListSchemaNode) childSchema).getKeyDefinition());
601 builder.withChild(childBuilder.build());
602 } else if (child instanceof LeafNode) {
603 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
604 final String nodeVal = ((LeafNode<String>) child).getValue();
605 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
606 Builders.leafBuilder((LeafSchemaNode) childSchema);
607 if (keys.contains(child.getNodeType())) {
608 leafBuilder.withValue(((LeafNode) child).getValue());
609 builder.withChild(leafBuilder.build());
612 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
613 leafBuilder.withValue(((LeafNode) child).getValue());
614 builder.withChild(leafBuilder.build());
617 if (defaultVal != null && defaultVal.equals(nodeVal)) {
618 leafBuilder.withValue(((LeafNode) child).getValue());
619 builder.withChild(leafBuilder.build());
627 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
628 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
629 final List<QName> keys) {
630 for (final MapEntryNode mapEntryNode : result.getValue()) {
631 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
632 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
633 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
634 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
635 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
636 builder.withChild(mapEntryBuilder.build());
640 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
641 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
642 final YangInstanceIdentifier actualPath, final boolean trim) {
643 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
644 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
645 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
646 if(child instanceof ContainerNode){
647 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
648 Builders.containerBuilder((ContainerSchemaNode) childSchema);
649 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
650 builder.withChild(builderChild.build());
651 } else if (child instanceof MapNode) {
652 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
653 Builders.mapBuilder((ListSchemaNode) childSchema);
654 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
655 ((ListSchemaNode) childSchema).getKeyDefinition());
656 builder.withChild(childBuilder.build());
657 } else if (child instanceof LeafNode) {
658 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
659 final String nodeVal = ((LeafNode<String>) child).getValue();
660 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
661 Builders.leafBuilder((LeafSchemaNode) childSchema);
663 if (defaultVal == null || !defaultVal.equals(nodeVal)) {
664 leafBuilder.withValue(((LeafNode) child).getValue());
665 builder.withChild(leafBuilder.build());
668 if (defaultVal != null && defaultVal.equals(nodeVal)) {
669 leafBuilder.withValue(((LeafNode) child).getValue());
670 builder.withChild(leafBuilder.build());
678 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
680 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
681 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
682 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
683 final String insert, final String point) {
684 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
685 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
686 return rWTransaction.submit();
690 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
692 private void postDataWithinTransaction(
693 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
694 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
695 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
696 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
699 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
700 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
701 final SchemaContext schemaContext, final String insert, final String point) {
702 if (insert == null) {
703 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
707 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
708 checkItemDoesNotExists(rWTransaction, datastore, path);
711 if(schemaNode instanceof ListSchemaNode){
712 final OrderedMapNode readList =
713 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
714 if (readList == null || readList.getValue().isEmpty()) {
715 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
717 rWTransaction.delete(datastore, path.getParent().getParent());
718 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
719 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
723 final OrderedLeafSetNode<?> readLeafList =
724 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
725 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
726 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
728 rWTransaction.delete(datastore, path.getParent());
729 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
730 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
736 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
739 if(schemaNode instanceof ListSchemaNode){
740 final OrderedMapNode readList =
741 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
742 if (readList == null || readList.getValue().isEmpty()) {
743 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
745 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
750 final OrderedLeafSetNode<?> readLeafList =
751 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
752 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
753 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
755 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
761 if (schemaNode instanceof ListSchemaNode) {
762 final OrderedMapNode readList =
763 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
764 if (readList == null || readList.getValue().isEmpty()) {
765 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
767 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
772 final OrderedLeafSetNode<?> readLeafList =
773 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
774 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
775 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
777 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
778 readLeafList, false);
783 throw new RestconfDocumentedException(
784 "Used bad value of insert parameter. Possible values are first, last, before or after, "
785 + "but was: " + insert);
789 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
790 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
791 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
792 final boolean before) {
793 rWTransaction.delete(datastore, path.getParent().getParent());
794 final InstanceIdentifierContext<?> instanceIdentifier =
795 ControllerContext.getInstance().toInstanceIdentifier(point);
797 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
798 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
807 final NormalizedNode<?, ?> emptySubtree =
808 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
809 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
810 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
812 checkItemDoesNotExists(rWTransaction, datastore, path);
813 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
815 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
816 checkItemDoesNotExists(rWTransaction, datastore, childPath);
817 rWTransaction.put(datastore, childPath, nodeChild);
822 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
823 final LogicalDatastoreType datastore,
824 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
825 final String point, final MapNode readList, final boolean before) {
826 rWTransaction.delete(datastore, path.getParent().getParent());
827 final InstanceIdentifierContext<?> instanceIdentifier =
828 ControllerContext.getInstance().toInstanceIdentifier(point);
830 for (final MapEntryNode mapEntryNode : readList.getValue()) {
831 if (mapEntryNode.getIdentifier()
832 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
841 final NormalizedNode<?, ?> emptySubtree =
842 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
843 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
844 for (final MapEntryNode mapEntryNode : readList.getValue()) {
846 checkItemDoesNotExists(rWTransaction, datastore, path);
847 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
849 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
850 checkItemDoesNotExists(rWTransaction, datastore, childPath);
851 rWTransaction.put(datastore, childPath, mapEntryNode);
856 private static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
857 final YangInstanceIdentifier parent = path.getParent();
858 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
859 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
861 if (dataSchemaNode instanceof ListSchemaNode) {
862 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
863 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
865 return dataSchemaNode;
867 if (dataSchemaNode instanceof LeafListSchemaNode) {
868 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
869 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
871 return dataSchemaNode;
873 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
876 private static void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction,
877 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
878 final SchemaContext schemaContext) {
879 final Collection<? extends NormalizedNode<?, ?>> children;
880 if (payload instanceof MapNode) {
881 children = ((MapNode) payload).getValue();
882 } else if (payload instanceof LeafSetNode) {
883 children = ((LeafSetNode<?>) payload).getValue();
885 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
889 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
890 if (children.isEmpty()) {
891 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
892 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
896 // Kick off batch existence check first...
897 final BatchedExistenceCheck check = BatchedExistenceCheck.start(rWTransaction, datastore, path, children);
899 // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
900 // result of the existence checks...
901 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
902 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
903 for (final NormalizedNode<?, ?> child : children) {
904 // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
905 // as that would allow us to skip the existence checks
906 rWTransaction.put(datastore, path.node(child.getIdentifier()), child);
909 // ... finally collect existence checks and abort the transaction if any of them failed.
910 final Entry<YangInstanceIdentifier, ReadFailedException> failure;
912 failure = check.getFailure();
913 } catch (InterruptedException e) {
914 rWTransaction.cancel();
915 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
918 if (failure != null) {
919 rWTransaction.cancel();
920 final ReadFailedException e = failure.getValue();
922 throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
923 ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
926 throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
931 private static void simplePostPut(final DOMDataReadWriteTransaction rWTransaction,
932 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
933 final SchemaContext schemaContext) {
934 checkItemDoesNotExists(rWTransaction, datastore, path);
935 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
936 rWTransaction.put(datastore, path, payload);
939 private static boolean doesItemExist(final DOMDataReadWriteTransaction rWTransaction,
940 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
942 return rWTransaction.exists(store, path).checkedGet();
943 } catch (ReadFailedException e) {
944 rWTransaction.cancel();
945 throw new RestconfDocumentedException("Could not determine the existence of path " + path,
946 e, e.getErrorList());
951 * Check if item already exists. Throws error if it does NOT already exist.
952 * @param rWTransaction Current transaction
953 * @param store Used datastore
954 * @param path Path to item to verify its existence
956 private static void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
957 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
958 if (!doesItemExist(rWTransaction, store, path)) {
959 final String errMsg = "Operation via Restconf was not executed because data does not exist";
960 LOG.trace("{}:{}", errMsg, path);
961 rWTransaction.cancel();
962 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
963 ErrorTag.DATA_MISSING);
968 * Check if item does NOT already exist. Throws error if it already exists.
969 * @param rWTransaction Current transaction
970 * @param store Used datastore
971 * @param path Path to item to verify its existence
973 private static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
974 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
975 if (doesItemExist(rWTransaction, store, path)) {
976 final String errMsg = "Operation via Restconf was not executed because data already exists";
977 LOG.trace("{}:{}", errMsg, path);
978 rWTransaction.cancel();
979 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
980 ErrorTag.DATA_EXISTS);
985 * PUT data and submit {@link DOMDataReadWriteTransaction}
990 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
991 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
992 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
993 final String insert, final String point) {
994 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
995 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
996 return readWriteTransaction.submit();
1000 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
1005 private void putDataWithinTransaction(
1006 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1007 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1008 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1009 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1012 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1013 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
1014 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1015 final String insert, final String point) {
1016 if (insert == null) {
1017 makePut(rWTransaction, datastore, path, payload, schemaContext);
1021 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1022 checkItemDoesNotExists(rWTransaction, datastore, path);
1025 if (schemaNode instanceof ListSchemaNode) {
1026 final OrderedMapNode readList =
1027 (OrderedMapNode) this.readConfigurationData(path.getParent());
1028 if (readList == null || readList.getValue().isEmpty()) {
1029 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1031 rWTransaction.delete(datastore, path.getParent());
1032 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1033 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
1036 final OrderedLeafSetNode<?> readLeafList =
1037 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1038 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1039 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1041 rWTransaction.delete(datastore, path.getParent());
1042 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1043 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1049 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1052 if (schemaNode instanceof ListSchemaNode) {
1053 final OrderedMapNode readList =
1054 (OrderedMapNode) this.readConfigurationData(path.getParent());
1055 if (readList == null || readList.getValue().isEmpty()) {
1056 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1058 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1062 final OrderedLeafSetNode<?> readLeafList =
1063 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1064 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1065 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1067 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1068 readLeafList, true);
1073 if (schemaNode instanceof ListSchemaNode) {
1074 final OrderedMapNode readList =
1075 (OrderedMapNode) this.readConfigurationData(path.getParent());
1076 if (readList == null || readList.getValue().isEmpty()) {
1077 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1079 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1083 final OrderedLeafSetNode<?> readLeafList =
1084 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1085 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
1086 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1088 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1089 readLeafList, false);
1094 throw new RestconfDocumentedException(
1095 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
1100 private static void insertWithPointLeafListPut(final DOMDataWriteTransaction tx,
1101 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1102 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1103 final boolean before) {
1104 tx.delete(datastore, path.getParent());
1105 final InstanceIdentifierContext<?> instanceIdentifier =
1106 ControllerContext.getInstance().toInstanceIdentifier(point);
1108 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1109 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1118 final NormalizedNode<?, ?> emptySubtree =
1119 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1120 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1121 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1123 simplePut(datastore, path, tx, schemaContext, payload);
1125 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1126 tx.put(datastore, childPath, nodeChild);
1131 private static void insertWithPointListPut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1132 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1133 final String point, final OrderedMapNode readList, final boolean before) {
1134 tx.delete(datastore, path.getParent());
1135 final InstanceIdentifierContext<?> instanceIdentifier =
1136 ControllerContext.getInstance().toInstanceIdentifier(point);
1138 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1139 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1148 final NormalizedNode<?, ?> emptySubtree =
1149 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1150 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1151 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1153 simplePut(datastore, path, tx, schemaContext, payload);
1155 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1156 tx.put(datastore, childPath, mapEntryNode);
1161 private static void makePut(final DOMDataWriteTransaction tx, final LogicalDatastoreType datastore,
1162 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1163 if (payload instanceof MapNode) {
1164 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1165 tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1166 ensureParentsByMerge(datastore, path, tx, schemaContext);
1167 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1168 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1169 tx.put(datastore, childPath, child);
1172 simplePut(datastore, path, tx, schemaContext, payload);
1176 private static void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1177 final DOMDataWriteTransaction tx, final SchemaContext schemaContext, final NormalizedNode<?, ?> payload) {
1178 ensureParentsByMerge(datastore, path, tx, schemaContext);
1179 tx.put(datastore, path, payload);
1182 private static CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1183 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1184 final YangInstanceIdentifier path) {
1185 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1186 checkItemExists(readWriteTransaction, datastore, path);
1187 readWriteTransaction.delete(datastore, path);
1188 return readWriteTransaction.submit();
1191 private static void deleteDataWithinTransaction(final DOMDataWriteTransaction tx,
1192 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
1193 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1194 tx.delete(datastore, path);
1197 private static void mergeDataWithinTransaction(final DOMDataWriteTransaction tx,
1198 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1199 final SchemaContext schemaContext) {
1200 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1201 ensureParentsByMerge(datastore, path, tx, schemaContext);
1203 // Since YANG Patch provides the option to specify what kind of operation for each edit,
1204 // OpenDaylight should not change it.
1205 tx.merge(datastore, path, payload);
1208 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1209 this.domDataBroker = domDataBroker;
1212 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1213 checkPreconditions();
1215 if (listener.isListening()) {
1219 final SchemaPath path = listener.getSchemaPath();
1220 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1221 .registerNotificationListener(listener, path);
1223 listener.setRegistration(registration);
1226 private static void ensureParentsByMerge(final LogicalDatastoreType store,
1227 final YangInstanceIdentifier normalizedPath, final DOMDataWriteTransaction tx,
1228 final SchemaContext schemaContext) {
1229 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1230 YangInstanceIdentifier rootNormalizedPath = null;
1232 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1234 while (it.hasNext()) {
1235 final PathArgument pathArgument = it.next();
1236 if (rootNormalizedPath == null) {
1237 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1241 normalizedPathWithoutChildArgs.add(pathArgument);
1245 if (normalizedPathWithoutChildArgs.isEmpty()) {
1249 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1251 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1252 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1253 tx.merge(store, rootNormalizedPath, parentStructure);
1256 private static final class PATCHStatusContextHelper {
1257 PATCHStatusContext status;
1259 public PATCHStatusContext getStatus() {
1263 public void setStatus(final PATCHStatusContext status) {
1264 this.status = status;