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;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.concurrent.CountDownLatch;
23 import javax.annotation.Nullable;
24 import javax.ws.rs.core.Response.Status;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
29 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
35 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
36 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
37 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
40 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
41 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
42 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
43 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
44 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.common.QName;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
51 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
53 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
61 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
62 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
63 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
64 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
65 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
66 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
67 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
68 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
70 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
74 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 public class BrokerFacade {
79 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
81 private final static BrokerFacade INSTANCE = new BrokerFacade();
82 private volatile DOMRpcService rpcService;
83 private volatile ConsumerSession context;
84 private DOMDataBroker domDataBroker;
85 private DOMNotificationService domNotification;
87 private BrokerFacade() {}
89 public void setRpcService(final DOMRpcService router) {
90 this.rpcService = router;
93 public void setDomNotificationService(final DOMNotificationService domNotification) {
94 this.domNotification = domNotification;
97 public void setContext(final ConsumerSession context) {
98 this.context = context;
101 public static BrokerFacade getInstance() {
102 return BrokerFacade.INSTANCE;
105 private void checkPreconditions() {
106 if ((this.context == null) || (this.domDataBroker == null)) {
107 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
112 * Read config data by path
118 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
119 return readConfigurationData(path, null);
123 * Read config data by path
128 * - value of with-defaults parameter
131 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
132 checkPreconditions();
133 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path, withDefa);
137 * Read config data from mount point by path.
140 * - mount point for reading data
145 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
146 final YangInstanceIdentifier path) {
147 return readConfigurationData(mountPoint, path, null);
151 * Read config data from mount point by path.
154 * - mount point for reading data
158 * - value of with-defaults parameter
161 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
162 final String withDefa) {
163 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
164 if (domDataBrokerService.isPresent()) {
165 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path,
168 final String errMsg = "DOM data broker service isn't available for mount point " + path;
170 throw new RestconfDocumentedException(errMsg);
174 * Read operational data by path.
180 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
181 checkPreconditions();
182 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
186 * Read operational data from mount point by path.
189 * - mount point for reading data
194 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
195 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
196 if (domDataBrokerService.isPresent()) {
197 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
199 final String errMsg = "DOM data broker service isn't available for mount point " + path;
201 throw new RestconfDocumentedException(errMsg);
205 * <b>PUT configuration data</b>
207 * Prepare result(status) for PUT operation and PUT data via transaction.
208 * Return wrapped status and future from PUT.
210 * @param globalSchema
211 * - used by merge parents (if contains list)
218 * @return wrapper of status and future of PUT
220 public PutResult commitConfigurationDataPut(
221 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
222 final String insert, final String point) {
223 Preconditions.checkNotNull(globalSchema);
224 Preconditions.checkNotNull(path);
225 Preconditions.checkNotNull(payload);
227 checkPreconditions();
229 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
230 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
232 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
233 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
234 return new PutResult(status, future);
238 * <b>PUT configuration data (Mount point)</b>
240 * Prepare result(status) for PUT operation and PUT data via transaction.
241 * Return wrapped status and future from PUT.
244 * - mount point for getting transaction for operation and schema
245 * context for merging parents(if contains list)
252 * @return wrapper of status and future of PUT
254 public PutResult commitMountPointDataPut(
255 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
256 final String insert, final String point) {
257 Preconditions.checkNotNull(mountPoint);
258 Preconditions.checkNotNull(path);
259 Preconditions.checkNotNull(payload);
261 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
262 if (domDataBrokerService.isPresent()) {
263 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
264 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
265 ? Status.OK : Status.CREATED;
266 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
267 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
269 return new PutResult(status, future);
271 final String errMsg = "DOM data broker service isn't available for mount point " + path;
273 throw new RestconfDocumentedException(errMsg);
276 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
277 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
279 // get new transaction and schema context on server or on mounted device
280 final SchemaContext schemaContext;
281 final DOMDataReadWriteTransaction patchTransaction;
282 if (mountPoint == null) {
283 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
284 patchTransaction = this.domDataBroker.newReadWriteTransaction();
286 schemaContext = mountPoint.getSchemaContext();
288 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
290 if (optional.isPresent()) {
291 patchTransaction = optional.get().newReadWriteTransaction();
293 // if mount point does not have broker it is not possible to continue and global error is reported
294 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
295 patchContext.getPatchId(), mountPoint.getIdentifier());
296 return new PATCHStatusContext(
297 patchContext.getPatchId(),
300 ImmutableList.of(new RestconfError(
301 ErrorType.APPLICATION,
302 ErrorTag.OPERATION_FAILED,
303 "DOM data broker service isn't available for mount point "
304 + mountPoint.getIdentifier()))
309 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
310 List<RestconfError> editErrors;
311 boolean withoutError = true;
313 for (final PATCHEntity patchEntity : patchContext.getData()) {
314 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
320 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
321 patchEntity.getNode(), schemaContext);
322 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
323 } catch (final RestconfDocumentedException e) {
324 LOG.error("Error call http PATCH operation {} on target {}",
326 patchEntity.getTargetNode().toString());
328 editErrors = new ArrayList<>();
329 editErrors.addAll(e.getErrors());
330 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
331 withoutError = false;
338 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
339 .getTargetNode(), patchEntity.getNode(), schemaContext);
340 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
341 } catch (final RestconfDocumentedException e) {
342 LOG.error("Error call http PATCH operation {} on target {}",
344 patchEntity.getTargetNode().toString());
346 editErrors = new ArrayList<>();
347 editErrors.addAll(e.getErrors());
348 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
349 withoutError = false;
356 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
358 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
359 } catch (final RestconfDocumentedException e) {
360 LOG.error("Error call http PATCH operation {} on target {}",
362 patchEntity.getTargetNode().toString());
364 editErrors = new ArrayList<>();
365 editErrors.addAll(e.getErrors());
366 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
367 withoutError = false;
374 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
376 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
377 } catch (final RestconfDocumentedException e) {
378 LOG.error("Error call http PATCH operation {} on target {}",
380 patchEntity.getTargetNode().toString());
382 editErrors = new ArrayList<>();
383 editErrors.addAll(e.getErrors());
384 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
385 withoutError = false;
392 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
393 patchEntity.getNode(), schemaContext);
394 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
395 } catch (final RestconfDocumentedException e) {
396 LOG.error("Error call http PATCH operation {} on target {}",
398 patchEntity.getTargetNode().toString());
400 editErrors = new ArrayList<>();
401 editErrors.addAll(e.getErrors());
402 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
403 withoutError = false;
408 LOG.error("Unsupported http PATCH operation {} on target {}",
410 patchEntity.getTargetNode().toString());
415 // if errors then cancel transaction and return error status
417 patchTransaction.cancel();
418 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
421 // if no errors commit transaction
422 final CountDownLatch waiter = new CountDownLatch(1);
423 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
424 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
426 Futures.addCallback(future, new FutureCallback<Void>() {
428 public void onSuccess(@Nullable final Void result) {
429 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
435 public void onFailure(final Throwable t) {
436 // if commit failed it is global error
437 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
438 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
439 false, ImmutableList.of(
440 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
446 return status.getStatus();
449 // POST configuration
450 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
451 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
452 final String insert, final String point) {
453 checkPreconditions();
454 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
455 globalSchema, insert, point);
458 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
459 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
460 final String insert, final String point) {
461 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
462 if (domDataBrokerService.isPresent()) {
463 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
464 payload, mountPoint.getSchemaContext(), insert, point);
466 final String errMsg = "DOM data broker service isn't available for mount point " + path;
468 throw new RestconfDocumentedException(errMsg);
471 // DELETE configuration
472 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
473 final YangInstanceIdentifier path) {
474 checkPreconditions();
475 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
478 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
479 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
480 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
481 if (domDataBrokerService.isPresent()) {
482 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
484 final String errMsg = "DOM data broker service isn't available for mount point " + path;
486 throw new RestconfDocumentedException(errMsg);
490 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
491 checkPreconditions();
492 if (this.rpcService == null) {
493 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
495 LOG.trace("Invoke RPC {} with input: {}", type, input);
496 return this.rpcService.invokeRpc(type, input);
499 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
500 final ListenerAdapter listener) {
501 checkPreconditions();
503 if (listener.isListening()) {
507 final YangInstanceIdentifier path = listener.getPath();
508 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
509 datastore, path, listener, scope);
511 listener.setRegistration(registration);
514 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
515 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
516 return readDataViaTransaction(transaction, datastore, path, null);
519 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
520 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
521 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
522 final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
523 final ReadDataResult<NormalizedNode<?, ?>> readData = new ReadDataResult<>();
524 final CountDownLatch responseWaiter = new CountDownLatch(1);
526 Futures.addCallback(listenableFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
529 public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
530 handlingCallback(null, datastore, path, result, readData);
531 responseWaiter.countDown();
535 public void onFailure(final Throwable t) {
536 responseWaiter.countDown();
537 handlingCallback(t, datastore, path, null, null);
542 responseWaiter.await();
543 } catch (final Exception e) {
544 final String msg = "Problem while waiting for response";
546 throw new RestconfDocumentedException(msg, e);
548 if (withDefa == null) {
549 return readData.getResult();
551 return prepareDataByParamWithDef(readData.getResult(), path, withDefa);
556 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
557 final YangInstanceIdentifier path, final String withDefa) {
567 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
570 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
571 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
572 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
573 if (result instanceof ContainerNode) {
574 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
575 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
576 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
577 return builder.build();
579 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
580 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
581 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
582 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
583 return builder.build();
587 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
588 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
589 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
590 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
591 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
592 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
593 if (child instanceof ContainerNode) {
594 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
595 Builders.containerBuilder((ContainerSchemaNode) childSchema);
596 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
597 builder.withChild(childBuilder.build());
598 } else if (child instanceof MapNode) {
599 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
600 Builders.mapBuilder((ListSchemaNode) childSchema);
601 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
602 ((ListSchemaNode) childSchema).getKeyDefinition());
603 builder.withChild(childBuilder.build());
604 } else if (child instanceof LeafNode) {
605 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
606 final String nodeVal = ((LeafNode<String>) child).getValue();
607 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
608 Builders.leafBuilder((LeafSchemaNode) childSchema);
609 if (keys.contains(child.getNodeType())) {
610 leafBuilder.withValue(((LeafNode) child).getValue());
611 builder.withChild(leafBuilder.build());
614 if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
615 leafBuilder.withValue(((LeafNode) child).getValue());
616 builder.withChild(leafBuilder.build());
619 if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
620 leafBuilder.withValue(((LeafNode) child).getValue());
621 builder.withChild(leafBuilder.build());
629 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
630 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
631 final List<QName> keys) {
632 for (final MapEntryNode mapEntryNode : result.getValue()) {
633 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
634 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
635 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
636 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
637 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
638 builder.withChild(mapEntryBuilder.build());
642 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
643 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
644 final YangInstanceIdentifier actualPath, final boolean trim) {
645 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
646 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
647 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
648 if(child instanceof ContainerNode){
649 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
650 Builders.containerBuilder((ContainerSchemaNode) childSchema);
651 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
652 builder.withChild(builderChild.build());
653 } else if (child instanceof MapNode) {
654 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
655 Builders.mapBuilder((ListSchemaNode) childSchema);
656 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
657 ((ListSchemaNode) childSchema).getKeyDefinition());
658 builder.withChild(childBuilder.build());
659 } else if (child instanceof LeafNode) {
660 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
661 final String nodeVal = ((LeafNode<String>) child).getValue();
662 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
663 Builders.leafBuilder((LeafSchemaNode) childSchema);
665 if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
666 leafBuilder.withValue(((LeafNode) child).getValue());
667 builder.withChild(leafBuilder.build());
670 if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
671 leafBuilder.withValue(((LeafNode) child).getValue());
672 builder.withChild(leafBuilder.build());
680 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
682 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
683 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
684 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
685 final String insert, final String point) {
686 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
687 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
688 return rWTransaction.submit();
692 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
694 private void postDataWithinTransaction(
695 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
696 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
697 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
698 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
701 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
702 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
703 final SchemaContext schemaContext, final String insert, final String point) {
704 if (insert == null) {
705 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);
790 private void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
791 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
792 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
793 final boolean before) {
794 rWTransaction.delete(datastore, path.getParent().getParent());
795 final InstanceIdentifierContext<?> instanceIdentifier =
796 ControllerContext.getInstance().toInstanceIdentifier(point);
798 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
799 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
808 final NormalizedNode<?, ?> emptySubtree =
809 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
810 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
811 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
813 checkItemDoesNotExists(rWTransaction, datastore, path);
814 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
816 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
817 checkItemDoesNotExists(rWTransaction, datastore, childPath);
818 rWTransaction.put(datastore, childPath, nodeChild);
823 private void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
824 final LogicalDatastoreType datastore,
825 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
826 final String point, final MapNode readList, final boolean before) {
827 rWTransaction.delete(datastore, path.getParent().getParent());
828 final InstanceIdentifierContext<?> instanceIdentifier =
829 ControllerContext.getInstance().toInstanceIdentifier(point);
831 for (final MapEntryNode mapEntryNode : readList.getValue()) {
832 if (mapEntryNode.getIdentifier()
833 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
842 final NormalizedNode<?, ?> emptySubtree =
843 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
844 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
845 for (final MapEntryNode mapEntryNode : readList.getValue()) {
847 checkItemDoesNotExists(rWTransaction, datastore, path);
848 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
850 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
851 checkItemDoesNotExists(rWTransaction, datastore, childPath);
852 rWTransaction.put(datastore, childPath, mapEntryNode);
857 private DataSchemaNode checkListAndOrderedType(final SchemaContext ctx,
858 final YangInstanceIdentifier path) {
859 final YangInstanceIdentifier parent = path.getParent();
860 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
861 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
863 if (dataSchemaNode instanceof ListSchemaNode) {
864 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
865 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
867 return dataSchemaNode;
869 if (dataSchemaNode instanceof LeafListSchemaNode) {
870 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
871 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
873 return dataSchemaNode;
875 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
878 private void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
879 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
880 if (payload instanceof MapNode) {
881 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
882 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
883 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
884 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
885 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
886 checkItemDoesNotExists(rWTransaction, datastore, childPath);
887 rWTransaction.put(datastore, childPath, child);
889 } else if (payload instanceof LeafSetNode) {
890 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
891 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
892 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
893 for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) payload).getValue()) {
894 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
895 checkItemDoesNotExists(rWTransaction, datastore, childPath);
896 rWTransaction.put(datastore, childPath, child);
899 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
903 private void simplePostPut(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
904 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
905 checkItemDoesNotExists(rWTransaction, datastore, path);
906 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
907 rWTransaction.put(datastore, path, payload);
911 * Check if item already exists. Throws error if it does NOT already exist.
912 * @param rWTransaction Current transaction
913 * @param store Used datastore
914 * @param path Path to item to verify its existence
916 private void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
917 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
918 final CountDownLatch responseWaiter = new CountDownLatch(1);
919 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
920 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
922 Futures.addCallback(future, new FutureCallback<Boolean>() {
924 public void onSuccess(@Nullable final Boolean result) {
925 handlingCallback(null, store, path, Optional.of(result), readData);
926 responseWaiter.countDown();
930 public void onFailure(final Throwable t) {
931 responseWaiter.countDown();
932 handlingCallback(t, store, path, null, null);
937 responseWaiter.await();
938 } catch (final Exception e) {
939 final String msg = "Problem while waiting for response";
941 throw new RestconfDocumentedException(msg, e);
944 if ((readData.getResult() == null) || !readData.getResult()) {
945 final String errMsg = "Operation via Restconf was not executed because data does not exist";
946 LOG.trace("{}:{}", errMsg, path);
947 rWTransaction.cancel();
948 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
949 ErrorTag.DATA_MISSING);
954 * Check if item does NOT already exist. Throws error if it already exists.
955 * @param rWTransaction Current transaction
956 * @param store Used datastore
957 * @param path Path to item to verify its existence
959 private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
960 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
961 final CountDownLatch responseWaiter = new CountDownLatch(1);
962 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
963 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
965 Futures.addCallback(future, new FutureCallback<Boolean>() {
967 public void onSuccess(@Nullable final Boolean result) {
968 handlingCallback(null, store, path, Optional.of(result), readData);
969 responseWaiter.countDown();
973 public void onFailure(final Throwable t) {
974 responseWaiter.countDown();
975 handlingCallback(t, store, path, null, null);
980 responseWaiter.await();
981 } catch (final Exception e) {
982 final String msg = "Problem while waiting for response";
984 throw new RestconfDocumentedException(msg, e);
987 if (readData.getResult()) {
988 final String errMsg = "Operation via Restconf was not executed because data already exists";
989 LOG.trace("{}:{}", errMsg, path);
990 rWTransaction.cancel();
991 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
992 ErrorTag.DATA_EXISTS);
997 * PUT data and submit {@link DOMDataReadWriteTransaction}
1002 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1003 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1004 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1005 final String insert, final String point) {
1006 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1007 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1008 return readWriteTransaction.submit();
1012 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
1017 private void putDataWithinTransaction(
1018 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1019 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1020 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1021 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1024 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1025 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
1026 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1027 final String insert, final String point) {
1028 if (insert == null) {
1029 makePut(rWTransaction, datastore, path, payload, schemaContext);
1031 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1032 checkItemDoesNotExists(rWTransaction, datastore, path);
1035 if (schemaNode instanceof ListSchemaNode) {
1036 final OrderedMapNode readList =
1037 (OrderedMapNode) this.readConfigurationData(path.getParent());
1038 if ((readList == null) || readList.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(), readList, schemaContext);
1046 final OrderedLeafSetNode<?> readLeafList =
1047 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1048 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1049 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1051 rWTransaction.delete(datastore, path.getParent());
1052 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1053 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1059 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1062 if (schemaNode instanceof ListSchemaNode) {
1063 final OrderedMapNode readList =
1064 (OrderedMapNode) this.readConfigurationData(path.getParent());
1065 if ((readList == null) || readList.getValue().isEmpty()) {
1066 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1068 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1072 final OrderedLeafSetNode<?> readLeafList =
1073 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1074 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1075 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1077 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1078 readLeafList, true);
1083 if (schemaNode instanceof ListSchemaNode) {
1084 final OrderedMapNode readList =
1085 (OrderedMapNode) this.readConfigurationData(path.getParent());
1086 if ((readList == null) || readList.getValue().isEmpty()) {
1087 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1089 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1093 final OrderedLeafSetNode<?> readLeafList =
1094 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1095 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1096 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1098 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1099 readLeafList, false);
1104 throw new RestconfDocumentedException(
1105 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1106 + "but was: " + insert);
1111 private void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1112 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1113 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1114 final boolean before) {
1115 rWTransaction.delete(datastore, path.getParent());
1116 final InstanceIdentifierContext<?> instanceIdentifier =
1117 ControllerContext.getInstance().toInstanceIdentifier(point);
1119 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1120 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1129 final NormalizedNode<?, ?> emptySubtree =
1130 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1131 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1132 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1134 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1136 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1137 rWTransaction.put(datastore, childPath, nodeChild);
1142 private void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1143 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1144 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1145 final boolean before) {
1146 rWTransaction.delete(datastore, path.getParent());
1147 final InstanceIdentifierContext<?> instanceIdentifier =
1148 ControllerContext.getInstance().toInstanceIdentifier(point);
1150 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1151 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1160 final NormalizedNode<?, ?> emptySubtree =
1161 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1162 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1163 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1165 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1167 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1168 rWTransaction.put(datastore, childPath, mapEntryNode);
1173 private void makePut(final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1174 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1175 if (payload instanceof MapNode) {
1176 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1177 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1178 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1179 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1180 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1181 writeTransaction.put(datastore, childPath, child);
1184 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1188 private void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1189 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1190 final NormalizedNode<?, ?> payload) {
1191 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1192 writeTransaction.put(datastore, path, payload);
1195 private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1196 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1197 final YangInstanceIdentifier path) {
1198 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1199 checkItemExists(readWriteTransaction, datastore, path);
1200 readWriteTransaction.delete(datastore, path);
1201 return readWriteTransaction.submit();
1204 private void deleteDataWithinTransaction(
1205 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1206 final YangInstanceIdentifier path) {
1207 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1208 writeTransaction.delete(datastore, path);
1211 private void mergeDataWithinTransaction(
1212 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1213 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1214 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1215 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1217 // merging is necessary only for lists otherwise we can call put method
1218 if (payload instanceof MapNode) {
1219 writeTransaction.merge(datastore, path, payload);
1221 writeTransaction.put(datastore, path, payload);
1225 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1226 this.domDataBroker = domDataBroker;
1230 * Helper class for result of transaction commit callback.
1231 * @param <T> Type of result
1233 private final class ReadDataResult<T> {
1240 void setResult(final T result) {
1241 this.result = result;
1246 * Set result from transaction commit callback.
1247 * @param t Throwable if transaction commit failed
1248 * @param datastore Datastore from which data are read
1249 * @param path Path from which data are read
1250 * @param result Result of read from {@code datastore}
1251 * @param readData Result value which will be set
1252 * @param <X> Result type
1254 protected final static <X> void handlingCallback(final Throwable t, final LogicalDatastoreType datastore,
1255 final YangInstanceIdentifier path, final Optional<X> result,
1256 final ReadDataResult<X> readData) {
1258 LOG.warn("Exception by reading {} via Restconf: {}", datastore.name(), path, t);
1259 throw new RestconfDocumentedException("Problem to get data from transaction.", t);
1261 LOG.debug("Reading result data from transaction.");
1262 if (result != null) {
1263 if (result.isPresent()) {
1264 readData.setResult(result.get());
1270 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1271 checkPreconditions();
1273 if (listener.isListening()) {
1277 final SchemaPath path = listener.getSchemaPath();
1278 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1279 .registerNotificationListener(listener, path);
1281 listener.setRegistration(registration);
1284 private final class PATCHStatusContextHelper {
1285 PATCHStatusContext status;
1287 public PATCHStatusContext getStatus() {
1291 public void setStatus(final PATCHStatusContext status) {
1292 this.status = status;
1296 private void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier normalizedPath,
1297 final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) {
1298 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1299 YangInstanceIdentifier rootNormalizedPath = null;
1301 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1303 while (it.hasNext()) {
1304 final PathArgument pathArgument = it.next();
1305 if (rootNormalizedPath == null) {
1306 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1310 normalizedPathWithoutChildArgs.add(pathArgument);
1314 if (normalizedPathWithoutChildArgs.isEmpty()) {
1318 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1320 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1321 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1322 rwTx.merge(store, rootNormalizedPath, parentStructure);