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 com.google.common.util.concurrent.ListenableFuture;
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.concurrent.CountDownLatch;
24 import javax.annotation.Nullable;
25 import javax.ws.rs.core.Response.Status;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
36 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
37 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
41 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
42 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
43 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
44 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
45 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
46 import org.opendaylight.yangtools.concepts.ListenerRegistration;
47 import org.opendaylight.yangtools.yang.common.QName;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
52 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
54 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
62 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
63 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
64 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
65 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
66 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
67 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
68 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
69 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
70 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
73 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
74 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
75 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
79 public class BrokerFacade {
80 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
82 private final static BrokerFacade INSTANCE = new BrokerFacade();
83 private volatile DOMRpcService rpcService;
84 private volatile ConsumerSession context;
85 private DOMDataBroker domDataBroker;
86 private DOMNotificationService domNotification;
88 private BrokerFacade() {}
90 public void setRpcService(final DOMRpcService router) {
91 this.rpcService = router;
94 public void setDomNotificationService(final DOMNotificationService domNotification) {
95 this.domNotification = domNotification;
98 public void setContext(final ConsumerSession context) {
99 this.context = context;
102 public static BrokerFacade getInstance() {
103 return BrokerFacade.INSTANCE;
106 private void checkPreconditions() {
107 if ((this.context == null) || (this.domDataBroker == null)) {
108 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
113 * Read config data by path
119 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
120 return readConfigurationData(path, null);
124 * Read config data by path
129 * - value of with-defaults parameter
132 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
133 checkPreconditions();
134 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path, withDefa);
138 * Read config data from mount point by path.
141 * - mount point for reading data
146 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
147 final YangInstanceIdentifier path) {
148 return readConfigurationData(mountPoint, path, null);
152 * Read config data from mount point by path.
155 * - mount point for reading data
159 * - value of with-defaults parameter
162 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
163 final String withDefa) {
164 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
165 if (domDataBrokerService.isPresent()) {
166 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path,
169 final String errMsg = "DOM data broker service isn't available for mount point " + path;
171 throw new RestconfDocumentedException(errMsg);
175 * Read operational data by path.
181 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
182 checkPreconditions();
183 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
187 * Read operational data from mount point by path.
190 * - mount point for reading data
195 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
196 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
197 if (domDataBrokerService.isPresent()) {
198 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
200 final String errMsg = "DOM data broker service isn't available for mount point " + path;
202 throw new RestconfDocumentedException(errMsg);
206 * <b>PUT configuration data</b>
208 * Prepare result(status) for PUT operation and PUT data via transaction.
209 * Return wrapped status and future from PUT.
211 * @param globalSchema
212 * - used by merge parents (if contains list)
219 * @return wrapper of status and future of PUT
221 public PutResult commitConfigurationDataPut(
222 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
223 final String insert, final String point) {
224 Preconditions.checkNotNull(globalSchema);
225 Preconditions.checkNotNull(path);
226 Preconditions.checkNotNull(payload);
228 checkPreconditions();
230 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
231 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
233 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
234 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
235 return new PutResult(status, future);
239 * <b>PUT configuration data (Mount point)</b>
241 * Prepare result(status) for PUT operation and PUT data via transaction.
242 * Return wrapped status and future from PUT.
245 * - mount point for getting transaction for operation and schema
246 * context for merging parents(if contains list)
253 * @return wrapper of status and future of PUT
255 public PutResult commitMountPointDataPut(
256 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
257 final String insert, final String point) {
258 Preconditions.checkNotNull(mountPoint);
259 Preconditions.checkNotNull(path);
260 Preconditions.checkNotNull(payload);
262 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
263 if (domDataBrokerService.isPresent()) {
264 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
265 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
266 ? Status.OK : Status.CREATED;
267 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
268 newReadWriteTransaction, CONFIGURATION, path, payload, mountPoint.getSchemaContext(), insert,
270 return new PutResult(status, future);
272 final String errMsg = "DOM data broker service isn't available for mount point " + path;
274 throw new RestconfDocumentedException(errMsg);
277 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext patchContext) throws Exception {
278 final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
280 // get new transaction and schema context on server or on mounted device
281 final SchemaContext schemaContext;
282 final DOMDataReadWriteTransaction patchTransaction;
283 if (mountPoint == null) {
284 schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
285 patchTransaction = this.domDataBroker.newReadWriteTransaction();
287 schemaContext = mountPoint.getSchemaContext();
289 final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
291 if (optional.isPresent()) {
292 patchTransaction = optional.get().newReadWriteTransaction();
294 // if mount point does not have broker it is not possible to continue and global error is reported
295 LOG.error("Http PATCH {} has failed - device {} does not support broker service",
296 patchContext.getPatchId(), mountPoint.getIdentifier());
297 return new PATCHStatusContext(
298 patchContext.getPatchId(),
301 ImmutableList.of(new RestconfError(
302 ErrorType.APPLICATION,
303 ErrorTag.OPERATION_FAILED,
304 "DOM data broker service isn't available for mount point "
305 + mountPoint.getIdentifier()))
310 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
311 List<RestconfError> editErrors;
312 boolean withoutError = true;
314 for (final PATCHEntity patchEntity : patchContext.getData()) {
315 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
321 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
322 patchEntity.getNode(), schemaContext);
323 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
324 } catch (final RestconfDocumentedException e) {
325 LOG.error("Error call http PATCH operation {} on target {}",
327 patchEntity.getTargetNode().toString());
329 editErrors = new ArrayList<>();
330 editErrors.addAll(e.getErrors());
331 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
332 withoutError = false;
339 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
340 .getTargetNode(), patchEntity.getNode(), schemaContext);
341 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
342 } catch (final RestconfDocumentedException e) {
343 LOG.error("Error call http PATCH operation {} on target {}",
345 patchEntity.getTargetNode().toString());
347 editErrors = new ArrayList<>();
348 editErrors.addAll(e.getErrors());
349 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
350 withoutError = false;
357 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
359 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
360 } catch (final RestconfDocumentedException e) {
361 LOG.error("Error call http PATCH operation {} on target {}",
363 patchEntity.getTargetNode().toString());
365 editErrors = new ArrayList<>();
366 editErrors.addAll(e.getErrors());
367 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
368 withoutError = false;
375 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
377 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
378 } catch (final RestconfDocumentedException e) {
379 LOG.error("Error call http PATCH operation {} on target {}",
381 patchEntity.getTargetNode().toString());
383 editErrors = new ArrayList<>();
384 editErrors.addAll(e.getErrors());
385 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
386 withoutError = false;
393 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
394 patchEntity.getNode(), schemaContext);
395 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
396 } catch (final RestconfDocumentedException e) {
397 LOG.error("Error call http PATCH operation {} on target {}",
399 patchEntity.getTargetNode().toString());
401 editErrors = new ArrayList<>();
402 editErrors.addAll(e.getErrors());
403 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
404 withoutError = false;
409 LOG.error("Unsupported http PATCH operation {} on target {}",
411 patchEntity.getTargetNode().toString());
416 // if errors then cancel transaction and return error status
418 patchTransaction.cancel();
419 return new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
422 // if no errors commit transaction
423 final CountDownLatch waiter = new CountDownLatch(1);
424 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
425 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
427 Futures.addCallback(future, new FutureCallback<Void>() {
429 public void onSuccess(@Nullable final Void result) {
430 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
436 public void onFailure(final Throwable t) {
437 // if commit failed it is global error
438 LOG.error("Http PATCH {} transaction commit has failed", patchContext.getPatchId());
439 status.setStatus(new PATCHStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
440 false, ImmutableList.of(
441 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
447 return status.getStatus();
450 // POST configuration
451 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
452 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
453 final String insert, final String point) {
454 checkPreconditions();
455 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
456 globalSchema, insert, point);
459 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
460 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
461 final String insert, final String point) {
462 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
463 if (domDataBrokerService.isPresent()) {
464 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
465 payload, mountPoint.getSchemaContext(), insert, point);
467 final String errMsg = "DOM data broker service isn't available for mount point " + path;
469 throw new RestconfDocumentedException(errMsg);
472 // DELETE configuration
473 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
474 final YangInstanceIdentifier path) {
475 checkPreconditions();
476 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
479 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
480 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
481 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
482 if (domDataBrokerService.isPresent()) {
483 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
485 final String errMsg = "DOM data broker service isn't available for mount point " + path;
487 throw new RestconfDocumentedException(errMsg);
491 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
492 checkPreconditions();
493 if (this.rpcService == null) {
494 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
496 LOG.trace("Invoke RPC {} with input: {}", type, input);
497 return this.rpcService.invokeRpc(type, input);
500 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
501 final ListenerAdapter listener) {
502 checkPreconditions();
504 if (listener.isListening()) {
508 final YangInstanceIdentifier path = listener.getPath();
509 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
510 datastore, path, listener, scope);
512 listener.setRegistration(registration);
515 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
516 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
517 return readDataViaTransaction(transaction, datastore, path, null);
520 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
521 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
522 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
523 final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
524 final ReadDataResult<NormalizedNode<?, ?>> readData = new ReadDataResult<>();
525 final CountDownLatch responseWaiter = new CountDownLatch(1);
527 Futures.addCallback(listenableFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
530 public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
531 handlingCallback(null, datastore, path, result, readData);
532 responseWaiter.countDown();
536 public void onFailure(final Throwable t) {
537 responseWaiter.countDown();
538 handlingCallback(t, datastore, path, null, null);
543 responseWaiter.await();
544 } catch (final Exception e) {
545 final String msg = "Problem while waiting for response";
547 throw new RestconfDocumentedException(msg, e);
549 if (withDefa == null) {
550 return readData.getResult();
552 return prepareDataByParamWithDef(readData.getResult(), path, withDefa);
557 private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
558 final YangInstanceIdentifier path, final String withDefa) {
568 throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
571 final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
572 final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
573 final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
574 if (result instanceof ContainerNode) {
575 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
576 Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
577 buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
578 return builder.build();
580 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
581 Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
582 buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
583 ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
584 return builder.build();
588 private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
589 final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
590 final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
591 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
592 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
593 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
594 if (child instanceof ContainerNode) {
595 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
596 Builders.containerBuilder((ContainerSchemaNode) childSchema);
597 buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
598 builder.withChild(childBuilder.build());
599 } else if (child instanceof MapNode) {
600 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
601 Builders.mapBuilder((ListSchemaNode) childSchema);
602 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
603 ((ListSchemaNode) childSchema).getKeyDefinition());
604 builder.withChild(childBuilder.build());
605 } else if (child instanceof LeafNode) {
606 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
607 final String nodeVal = ((LeafNode<String>) child).getValue();
608 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
609 Builders.leafBuilder((LeafSchemaNode) childSchema);
610 if (keys.contains(child.getNodeType())) {
611 leafBuilder.withValue(((LeafNode) child).getValue());
612 builder.withChild(leafBuilder.build());
615 if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
616 leafBuilder.withValue(((LeafNode) child).getValue());
617 builder.withChild(leafBuilder.build());
620 if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
621 leafBuilder.withValue(((LeafNode) child).getValue());
622 builder.withChild(leafBuilder.build());
630 private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
631 final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
632 final List<QName> keys) {
633 for (final MapEntryNode mapEntryNode : result.getValue()) {
634 final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
635 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
636 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
637 Builders.mapEntryBuilder((ListSchemaNode) childSchema);
638 buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
639 builder.withChild(mapEntryBuilder.build());
643 private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
644 final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
645 final YangInstanceIdentifier actualPath, final boolean trim) {
646 for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
647 final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
648 final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
649 if(child instanceof ContainerNode){
650 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
651 Builders.containerBuilder((ContainerSchemaNode) childSchema);
652 buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
653 builder.withChild(builderChild.build());
654 } else if (child instanceof MapNode) {
655 final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
656 Builders.mapBuilder((ListSchemaNode) childSchema);
657 buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
658 ((ListSchemaNode) childSchema).getKeyDefinition());
659 builder.withChild(childBuilder.build());
660 } else if (child instanceof LeafNode) {
661 final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
662 final String nodeVal = ((LeafNode<String>) child).getValue();
663 final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
664 Builders.leafBuilder((LeafSchemaNode) childSchema);
666 if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
667 leafBuilder.withValue(((LeafNode) child).getValue());
668 builder.withChild(leafBuilder.build());
671 if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
672 leafBuilder.withValue(((LeafNode) child).getValue());
673 builder.withChild(leafBuilder.build());
681 * POST data and submit transaction {@link DOMDataReadWriteTransaction}
683 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
684 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
685 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
686 final String insert, final String point) {
687 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
688 postData(rWTransaction, datastore, path, payload, schemaContext, insert, point);
689 return rWTransaction.submit();
693 * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}
695 private void postDataWithinTransaction(
696 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
697 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
698 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
699 postData(rWTransaction, datastore, path, payload, schemaContext, null, null);
702 private void postData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
703 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
704 final SchemaContext schemaContext, final String insert, final String point) {
705 if (insert == null) {
706 makeNormalPost(rWTransaction, datastore, path, payload, schemaContext);
708 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
709 checkItemDoesNotExists(rWTransaction, datastore, path);
712 if(schemaNode instanceof ListSchemaNode){
713 final OrderedMapNode readList =
714 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
715 if ((readList == null) || readList.getValue().isEmpty()) {
716 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
718 rWTransaction.delete(datastore, path.getParent().getParent());
719 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
720 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readList,
724 final OrderedLeafSetNode readLeafList =
725 (OrderedLeafSetNode) readConfigurationData(path.getParent());
726 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
727 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
729 rWTransaction.delete(datastore, path.getParent());
730 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
731 makeNormalPost(rWTransaction, datastore, path.getParent().getParent(), readLeafList,
737 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
740 if(schemaNode instanceof ListSchemaNode){
741 final OrderedMapNode readList =
742 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
743 if ((readList == null) || readList.getValue().isEmpty()) {
744 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
746 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
751 final OrderedLeafSetNode<?> readLeafList =
752 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
753 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
754 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
756 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
762 if (schemaNode instanceof ListSchemaNode) {
763 final OrderedMapNode readList =
764 (OrderedMapNode) this.readConfigurationData(path.getParent().getParent());
765 if ((readList == null) || readList.getValue().isEmpty()) {
766 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
768 insertWithPointListPost(rWTransaction, datastore, path, payload, schemaContext, point,
773 final OrderedLeafSetNode<?> readLeafList =
774 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
775 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
776 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
778 insertWithPointLeafListPost(rWTransaction, datastore, path, payload, schemaContext, point,
779 readLeafList, false);
784 throw new RestconfDocumentedException(
785 "Used bad value of insert parameter. Possible values are first, last, before or after, "
786 + "but was: " + insert);
791 private void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
792 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
793 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
794 final boolean before) {
795 rWTransaction.delete(datastore, path.getParent().getParent());
796 final InstanceIdentifierContext<?> instanceIdentifier =
797 ControllerContext.getInstance().toInstanceIdentifier(point);
799 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
800 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
809 final NormalizedNode<?, ?> emptySubtree =
810 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
811 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
812 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
814 checkItemDoesNotExists(rWTransaction, datastore, path);
815 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
817 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
818 checkItemDoesNotExists(rWTransaction, datastore, childPath);
819 rWTransaction.put(datastore, childPath, nodeChild);
824 private void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
825 final LogicalDatastoreType datastore,
826 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
827 final String point, final MapNode readList, final boolean before) {
828 rWTransaction.delete(datastore, path.getParent().getParent());
829 final InstanceIdentifierContext<?> instanceIdentifier =
830 ControllerContext.getInstance().toInstanceIdentifier(point);
832 for (final MapEntryNode mapEntryNode : readList.getValue()) {
833 if (mapEntryNode.getIdentifier()
834 .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
843 final NormalizedNode<?, ?> emptySubtree =
844 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
845 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
846 for (final MapEntryNode mapEntryNode : readList.getValue()) {
848 checkItemDoesNotExists(rWTransaction, datastore, path);
849 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
851 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
852 checkItemDoesNotExists(rWTransaction, datastore, childPath);
853 rWTransaction.put(datastore, childPath, mapEntryNode);
858 private DataSchemaNode checkListAndOrderedType(final SchemaContext ctx,
859 final YangInstanceIdentifier path) {
860 final YangInstanceIdentifier parent = path.getParent();
861 final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).getChild(parent);
862 final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
864 if (dataSchemaNode instanceof ListSchemaNode) {
865 if(!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
866 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
868 return dataSchemaNode;
870 if (dataSchemaNode instanceof LeafListSchemaNode) {
871 if(!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
872 throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user leaf-list.");
874 return dataSchemaNode;
876 throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
879 private void makeNormalPost(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
880 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
881 if (payload instanceof MapNode) {
882 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
883 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
884 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
885 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
886 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
887 checkItemDoesNotExists(rWTransaction, datastore, childPath);
888 rWTransaction.put(datastore, childPath, child);
890 } else if (payload instanceof LeafSetNode) {
891 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
892 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
893 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
894 for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) payload).getValue()) {
895 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
896 checkItemDoesNotExists(rWTransaction, datastore, childPath);
897 rWTransaction.put(datastore, childPath, child);
900 simplePostPut(rWTransaction, datastore, path, payload, schemaContext);
904 private void simplePostPut(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
905 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
906 checkItemDoesNotExists(rWTransaction, datastore, path);
907 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
908 rWTransaction.put(datastore, path, payload);
912 * Check if item already exists. Throws error if it does NOT already exist.
913 * @param rWTransaction Current transaction
914 * @param store Used datastore
915 * @param path Path to item to verify its existence
917 private void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
918 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
919 final CountDownLatch responseWaiter = new CountDownLatch(1);
920 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
921 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
923 Futures.addCallback(future, new FutureCallback<Boolean>() {
925 public void onSuccess(@Nullable final Boolean result) {
926 handlingCallback(null, store, path, Optional.of(result), readData);
927 responseWaiter.countDown();
931 public void onFailure(final Throwable t) {
932 responseWaiter.countDown();
933 handlingCallback(t, store, path, null, null);
938 responseWaiter.await();
939 } catch (final Exception e) {
940 final String msg = "Problem while waiting for response";
942 throw new RestconfDocumentedException(msg, e);
945 if ((readData.getResult() == null) || !readData.getResult()) {
946 final String errMsg = "Operation via Restconf was not executed because data does not exist";
947 LOG.trace("{}:{}", errMsg, path);
948 rWTransaction.cancel();
949 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
950 ErrorTag.DATA_MISSING);
955 * Check if item does NOT already exist. Throws error if it already exists.
956 * @param rWTransaction Current transaction
957 * @param store Used datastore
958 * @param path Path to item to verify its existence
960 private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
961 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
962 final CountDownLatch responseWaiter = new CountDownLatch(1);
963 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
964 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
966 Futures.addCallback(future, new FutureCallback<Boolean>() {
968 public void onSuccess(@Nullable final Boolean result) {
969 handlingCallback(null, store, path, Optional.of(result), readData);
970 responseWaiter.countDown();
974 public void onFailure(final Throwable t) {
975 responseWaiter.countDown();
976 handlingCallback(t, store, path, null, null);
981 responseWaiter.await();
982 } catch (final Exception e) {
983 final String msg = "Problem while waiting for response";
985 throw new RestconfDocumentedException(msg, e);
988 if (readData.getResult()) {
989 final String errMsg = "Operation via Restconf was not executed because data already exists";
990 LOG.trace("{}:{}", errMsg, path);
991 rWTransaction.cancel();
992 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
993 ErrorTag.DATA_EXISTS);
998 * PUT data and submit {@link DOMDataReadWriteTransaction}
1003 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
1004 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1005 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1006 final String insert, final String point) {
1007 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
1008 putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
1009 return readWriteTransaction.submit();
1013 * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}
1018 private void putDataWithinTransaction(
1019 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1020 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1021 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1022 putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
1025 // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
1026 private void putData(final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
1027 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
1028 final String insert, final String point) {
1029 if (insert == null) {
1030 makePut(rWTransaction, datastore, path, payload, schemaContext);
1032 final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
1033 checkItemDoesNotExists(rWTransaction, datastore, path);
1036 if (schemaNode instanceof ListSchemaNode) {
1037 final OrderedMapNode readList =
1038 (OrderedMapNode) this.readConfigurationData(path.getParent());
1039 if ((readList == null) || readList.getValue().isEmpty()) {
1040 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1042 rWTransaction.delete(datastore, path.getParent());
1043 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1044 makePut(rWTransaction, datastore, path.getParent(), readList, schemaContext);
1047 final OrderedLeafSetNode<?> readLeafList =
1048 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1049 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1050 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1052 rWTransaction.delete(datastore, path.getParent());
1053 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1054 makePut(rWTransaction, datastore, path.getParent(), readLeafList,
1060 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1063 if (schemaNode instanceof ListSchemaNode) {
1064 final OrderedMapNode readList =
1065 (OrderedMapNode) this.readConfigurationData(path.getParent());
1066 if ((readList == null) || readList.getValue().isEmpty()) {
1067 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1069 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1073 final OrderedLeafSetNode<?> readLeafList =
1074 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1075 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1076 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1078 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1079 readLeafList, true);
1084 if (schemaNode instanceof ListSchemaNode) {
1085 final OrderedMapNode readList =
1086 (OrderedMapNode) this.readConfigurationData(path.getParent());
1087 if ((readList == null) || readList.getValue().isEmpty()) {
1088 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1090 insertWithPointListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1094 final OrderedLeafSetNode<?> readLeafList =
1095 (OrderedLeafSetNode<?>) readConfigurationData(path.getParent());
1096 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
1097 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1099 insertWithPointLeafListPut(rWTransaction, datastore, path, payload, schemaContext, point,
1100 readLeafList, false);
1105 throw new RestconfDocumentedException(
1106 "Used bad value of insert parameter. Possible values are first, last, before or after, "
1107 + "but was: " + insert);
1112 private void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction,
1113 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1114 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
1115 final boolean before) {
1116 rWTransaction.delete(datastore, path.getParent());
1117 final InstanceIdentifierContext<?> instanceIdentifier =
1118 ControllerContext.getInstance().toInstanceIdentifier(point);
1120 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1121 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1130 final NormalizedNode<?, ?> emptySubtree =
1131 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1132 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1133 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
1135 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1137 final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
1138 rWTransaction.put(datastore, childPath, nodeChild);
1143 private void insertWithPointListPut(final DOMDataReadWriteTransaction rWTransaction,
1144 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
1145 final SchemaContext schemaContext, final String point, final OrderedMapNode readList,
1146 final boolean before) {
1147 rWTransaction.delete(datastore, path.getParent());
1148 final InstanceIdentifierContext<?> instanceIdentifier =
1149 ControllerContext.getInstance().toInstanceIdentifier(point);
1151 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1152 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
1161 final NormalizedNode<?, ?> emptySubtree =
1162 ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
1163 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1164 for (final MapEntryNode mapEntryNode : readList.getValue()) {
1166 simplePut(datastore, path, rWTransaction, schemaContext, payload);
1168 final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
1169 rWTransaction.put(datastore, childPath, mapEntryNode);
1174 private void makePut(final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1175 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1176 if (payload instanceof MapNode) {
1177 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
1178 writeTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
1179 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1180 for (final MapEntryNode child : ((MapNode) payload).getValue()) {
1181 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
1182 writeTransaction.put(datastore, childPath, child);
1185 simplePut(datastore, path, writeTransaction, schemaContext, payload);
1189 private void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
1190 final DOMDataReadWriteTransaction writeTransaction, final SchemaContext schemaContext,
1191 final NormalizedNode<?, ?> payload) {
1192 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1193 writeTransaction.put(datastore, path, payload);
1196 private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
1197 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
1198 final YangInstanceIdentifier path) {
1199 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
1200 checkItemExists(readWriteTransaction, datastore, path);
1201 readWriteTransaction.delete(datastore, path);
1202 return readWriteTransaction.submit();
1205 private void deleteDataWithinTransaction(
1206 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1207 final YangInstanceIdentifier path) {
1208 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
1209 writeTransaction.delete(datastore, path);
1212 private void mergeDataWithinTransaction(
1213 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
1214 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
1215 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
1216 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
1218 // merging is necessary only for lists otherwise we can call put method
1219 if (payload instanceof MapNode) {
1220 writeTransaction.merge(datastore, path, payload);
1222 writeTransaction.put(datastore, path, payload);
1226 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
1227 this.domDataBroker = domDataBroker;
1231 * Helper class for result of transaction commit callback.
1232 * @param <T> Type of result
1234 private final class ReadDataResult<T> {
1241 void setResult(final T result) {
1242 this.result = result;
1247 * Set result from transaction commit callback.
1248 * @param t Throwable if transaction commit failed
1249 * @param datastore Datastore from which data are read
1250 * @param path Path from which data are read
1251 * @param result Result of read from {@code datastore}
1252 * @param readData Result value which will be set
1253 * @param <X> Result type
1255 protected final static <X> void handlingCallback(final Throwable t, final LogicalDatastoreType datastore,
1256 final YangInstanceIdentifier path, final Optional<X> result,
1257 final ReadDataResult<X> readData) {
1259 LOG.warn("Exception by reading {} via Restconf: {}", datastore.name(), path, t);
1260 throw new RestconfDocumentedException("Problem to get data from transaction.", t);
1262 LOG.debug("Reading result data from transaction.");
1263 if (result != null) {
1264 if (result.isPresent()) {
1265 readData.setResult(result.get());
1271 public void registerToListenNotification(final NotificationListenerAdapter listener) {
1272 checkPreconditions();
1274 if (listener.isListening()) {
1278 final SchemaPath path = listener.getSchemaPath();
1279 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
1280 .registerNotificationListener(listener, path);
1282 listener.setRegistration(registration);
1285 private final class PATCHStatusContextHelper {
1286 PATCHStatusContext status;
1288 public PATCHStatusContext getStatus() {
1292 public void setStatus(final PATCHStatusContext status) {
1293 this.status = status;
1297 private void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier normalizedPath,
1298 final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) {
1299 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
1300 YangInstanceIdentifier rootNormalizedPath = null;
1302 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
1304 while (it.hasNext()) {
1305 final PathArgument pathArgument = it.next();
1306 if (rootNormalizedPath == null) {
1307 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
1311 normalizedPathWithoutChildArgs.add(pathArgument);
1315 if (normalizedPathWithoutChildArgs.isEmpty()) {
1319 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
1321 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
1322 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
1323 rwTx.merge(store, rootNormalizedPath, parentStructure);