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.collect.Lists;
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.data.api.YangInstanceIdentifier;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
49 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
52 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
54 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 public class BrokerFacade {
59 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
61 private final static BrokerFacade INSTANCE = new BrokerFacade();
62 private volatile DOMRpcService rpcService;
63 private volatile ConsumerSession context;
64 private DOMDataBroker domDataBroker;
65 private DOMNotificationService domNotification;
67 private BrokerFacade() {}
69 public void setRpcService(final DOMRpcService router) {
70 this.rpcService = router;
73 public void setDomNotificationService(final DOMNotificationService domNotification) {
74 this.domNotification = domNotification;
77 public void setContext(final ConsumerSession context) {
78 this.context = context;
81 public static BrokerFacade getInstance() {
82 return BrokerFacade.INSTANCE;
85 private void checkPreconditions() {
86 if ((this.context == null) || (this.domDataBroker == null)) {
87 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
92 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
94 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path);
97 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
98 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
99 if (domDataBrokerService.isPresent()) {
100 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path);
102 final String errMsg = "DOM data broker service isn't available for mount point " + path;
104 throw new RestconfDocumentedException(errMsg);
108 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
109 checkPreconditions();
110 return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
113 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
114 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
115 if (domDataBrokerService.isPresent()) {
116 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
118 final String errMsg = "DOM data broker service isn't available for mount point " + path;
120 throw new RestconfDocumentedException(errMsg);
124 * <b>PUT configuration data</b>
126 * Prepare result(status) for PUT operation and PUT data via transaction.
127 * Return wrapped status and future from PUT.
129 * @param globalSchema
130 * - used by merge parents (if contains list)
135 * @return wrapper of status and future of PUT
137 public PutResult commitConfigurationDataPut(
138 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
139 Preconditions.checkNotNull(globalSchema);
140 Preconditions.checkNotNull(path);
141 Preconditions.checkNotNull(payload);
143 checkPreconditions();
145 final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
146 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
148 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
149 newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema);
150 return new PutResult(status, future);
154 * <b>PUT configuration data (Mount point)</b>
156 * Prepare result(status) for PUT operation and PUT data via transaction.
157 * Return wrapped status and future from PUT.
160 * - mount point for getting transaction for operation and schema
161 * context for merging parents(if contains list)
166 * @return wrapper of status and future of PUT
168 public PutResult commitMountPointDataPut(
169 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
170 Preconditions.checkNotNull(mountPoint);
171 Preconditions.checkNotNull(path);
172 Preconditions.checkNotNull(payload);
174 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
175 if (domDataBrokerService.isPresent()) {
176 final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
177 final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
178 ? Status.OK : Status.CREATED;
179 final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
180 newReadWriteTransaction, CONFIGURATION, path,
181 payload, mountPoint.getSchemaContext());
182 return new PutResult(status, future);
184 final String errMsg = "DOM data broker service isn't available for mount point " + path;
186 throw new RestconfDocumentedException(errMsg);
189 public PATCHStatusContext patchConfigurationDataWithinTransaction(final PATCHContext context,
190 final SchemaContext globalSchema)
192 final DOMDataReadWriteTransaction patchTransaction = this.domDataBroker.newReadWriteTransaction();
193 final List<PATCHStatusEntity> editCollection = new ArrayList<>();
195 List<RestconfError> editErrors;
196 int errorCounter = 0;
198 for (final PATCHEntity patchEntity : context.getData()) {
199 final PATCHEditOperation operation = PATCHEditOperation.valueOf(patchEntity.getOperation().toUpperCase());
203 if (errorCounter == 0) {
205 postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
206 patchEntity.getNode(), globalSchema);
207 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
208 } catch (final RestconfDocumentedException e) {
209 editErrors = new ArrayList<>();
210 editErrors.addAll(e.getErrors());
211 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
217 if (errorCounter == 0) {
219 putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
220 .getTargetNode(), patchEntity.getNode(), globalSchema);
221 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
222 } catch (final RestconfDocumentedException e) {
223 editErrors = new ArrayList<>();
224 editErrors.addAll(e.getErrors());
225 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
231 if (errorCounter == 0) {
233 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
235 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
236 } catch (final RestconfDocumentedException e) {
237 editErrors = new ArrayList<>();
238 editErrors.addAll(e.getErrors());
239 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
245 if (errorCounter == 0) {
247 deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
249 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
250 } catch (final RestconfDocumentedException e) {
251 LOG.error("Error removing {} by {} operation", patchEntity.getTargetNode().toString(),
252 patchEntity.getEditId(), e);
257 if (errorCounter == 0) {
259 mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
260 patchEntity.getNode(), globalSchema);
261 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), true, null));
262 } catch (final RestconfDocumentedException e) {
263 editErrors = new ArrayList<>();
264 editErrors.addAll(e.getErrors());
265 editCollection.add(new PATCHStatusEntity(patchEntity.getEditId(), false, editErrors));
273 // if errors then cancel transaction and return error status
274 if (errorCounter != 0) {
275 patchTransaction.cancel();
276 return new PATCHStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
279 // if no errors commit transaction
280 final CountDownLatch waiter = new CountDownLatch(1);
281 final CheckedFuture<Void, TransactionCommitFailedException> future = patchTransaction.submit();
282 final PATCHStatusContextHelper status = new PATCHStatusContextHelper();
284 Futures.addCallback(future, new FutureCallback<Void>() {
286 public void onSuccess(@Nullable final Void result) {
287 status.setStatus(new PATCHStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
293 public void onFailure(final Throwable t) {
294 // if commit failed it is global error
295 status.setStatus(new PATCHStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
296 false, Lists.newArrayList(
297 new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, t.getMessage()))));
303 return status.getStatus();
306 // POST configuration
307 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
308 final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
309 checkPreconditions();
310 return postDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, globalSchema);
313 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
314 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
315 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
316 if (domDataBrokerService.isPresent()) {
317 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
318 payload, mountPoint.getSchemaContext());
320 final String errMsg = "DOM data broker service isn't available for mount point " + path;
322 throw new RestconfDocumentedException(errMsg);
325 // DELETE configuration
326 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
327 final YangInstanceIdentifier path) {
328 checkPreconditions();
329 return deleteDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
332 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
333 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
334 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
335 if (domDataBrokerService.isPresent()) {
336 return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
338 final String errMsg = "DOM data broker service isn't available for mount point " + path;
340 throw new RestconfDocumentedException(errMsg);
344 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
345 checkPreconditions();
346 if (this.rpcService == null) {
347 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
349 LOG.trace("Invoke RPC {} with input: {}", type, input);
350 return this.rpcService.invokeRpc(type, input);
353 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
354 final ListenerAdapter listener) {
355 checkPreconditions();
357 if (listener.isListening()) {
361 final YangInstanceIdentifier path = listener.getPath();
362 final ListenerRegistration<DOMDataChangeListener> registration = this.domDataBroker.registerDataChangeListener(
363 datastore, path, listener, scope);
365 listener.setRegistration(registration);
368 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
369 final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
370 LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
371 final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
372 final ReadDataResult<NormalizedNode<?, ?>> readData = new ReadDataResult<>();
373 final CountDownLatch responseWaiter = new CountDownLatch(1);
375 Futures.addCallback(listenableFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
378 public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
379 responseWaiter.countDown();
380 handlingCallback(null, datastore, path, result, readData);
384 public void onFailure(final Throwable t) {
385 responseWaiter.countDown();
386 handlingCallback(t, datastore, path, null, null);
391 responseWaiter.await();
392 } catch (final Exception e) {
393 final String msg = "Problem while waiting for response";
395 throw new RestconfDocumentedException(msg, e);
397 return readData.getResult();
400 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
401 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
402 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
403 // FIXME: This is doing correct post for container and list children
404 // not sure if this will work for choice case
405 if(payload instanceof MapNode) {
406 LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
407 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
408 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
409 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
410 for(final MapEntryNode child : ((MapNode) payload).getValue()) {
411 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
412 checkItemDoesNotExists(rWTransaction, datastore, childPath);
413 rWTransaction.put(datastore, childPath, child);
416 checkItemDoesNotExists(rWTransaction,datastore, path);
417 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
418 rWTransaction.put(datastore, path, payload);
420 return rWTransaction.submit();
423 private void postDataWithinTransaction(
424 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
425 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
426 // FIXME: This is doing correct post for container and list children
427 // not sure if this will work for choice case
428 if(payload instanceof MapNode) {
429 LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
430 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
431 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
432 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
433 for(final MapEntryNode child : ((MapNode) payload).getValue()) {
434 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
435 checkItemDoesNotExists(rWTransaction, datastore, childPath);
436 rWTransaction.put(datastore, childPath, child);
439 checkItemDoesNotExists(rWTransaction,datastore, path);
440 ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
441 rWTransaction.put(datastore, path, payload);
446 * Check if item already exists. Throws error if it does NOT already exist.
447 * @param rWTransaction Current transaction
448 * @param store Used datastore
449 * @param path Path to item to verify its existence
451 private void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
452 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
453 final CountDownLatch responseWaiter = new CountDownLatch(1);
454 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
455 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
457 Futures.addCallback(future, new FutureCallback<Boolean>() {
459 public void onSuccess(@Nullable final Boolean result) {
460 responseWaiter.countDown();
461 handlingCallback(null, store, path, Optional.of(result), readData);
465 public void onFailure(final Throwable t) {
466 responseWaiter.countDown();
467 handlingCallback(t, store, path, null, null);
472 responseWaiter.await();
473 } catch (final Exception e) {
474 final String msg = "Problem while waiting for response";
476 throw new RestconfDocumentedException(msg, e);
479 if ((readData.getResult() == null) || !readData.getResult()) {
480 final String errMsg = "Operation via Restconf was not executed because data does not exist";
481 LOG.trace("{}:{}", errMsg, path);
482 rWTransaction.cancel();
483 throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
484 ErrorTag.DATA_MISSING);
489 * Check if item does NOT already exist. Throws error if it already exists.
490 * @param rWTransaction Current transaction
491 * @param store Used datastore
492 * @param path Path to item to verify its existence
494 private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
495 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
496 final CountDownLatch responseWaiter = new CountDownLatch(1);
497 final ReadDataResult<Boolean> readData = new ReadDataResult<>();
498 final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
500 Futures.addCallback(future, new FutureCallback<Boolean>() {
502 public void onSuccess(@Nullable final Boolean result) {
503 responseWaiter.countDown();
504 handlingCallback(null, store, path, Optional.of(result), readData);
508 public void onFailure(final Throwable t) {
509 responseWaiter.countDown();
510 handlingCallback(t, store, path, null, null);
515 responseWaiter.await();
516 } catch (final Exception e) {
517 final String msg = "Problem while waiting for response";
519 throw new RestconfDocumentedException(msg, e);
522 if (readData.getResult()) {
523 final String errMsg = "Operation via Restconf was not executed because data already exists";
524 LOG.trace("{}:{}", errMsg, path);
525 rWTransaction.cancel();
526 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
527 ErrorTag.DATA_EXISTS);
531 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
532 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
533 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
534 LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
535 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
536 writeTransaction.put(datastore, path, payload);
537 return writeTransaction.submit();
540 private void putDataWithinTransaction(
541 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
542 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
543 LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
544 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
545 writeTransaction.put(datastore, path, payload);
548 private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
549 final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
550 final YangInstanceIdentifier path) {
551 LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
552 checkItemExists(readWriteTransaction, datastore, path);
553 readWriteTransaction.delete(datastore, path);
554 return readWriteTransaction.submit();
557 private void deleteDataWithinTransaction(
558 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
559 final YangInstanceIdentifier path) {
560 LOG.trace("Delete {} within Restconf PATCH: {}", datastore.name(), path);
561 writeTransaction.delete(datastore, path);
564 private void mergeDataWithinTransaction(
565 final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
566 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
567 LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
568 ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
570 // merging is necessary only for lists otherwise we can call put method
571 if (payload instanceof MapNode) {
572 writeTransaction.merge(datastore, path, payload);
574 writeTransaction.put(datastore, path, payload);
578 public void setDomDataBroker(final DOMDataBroker domDataBroker) {
579 this.domDataBroker = domDataBroker;
583 * Helper class for result of transaction commit callback.
584 * @param <T> Type of result
586 private final class ReadDataResult<T> {
593 void setResult(final T result) {
594 this.result = result;
599 * Set result from transaction commit callback.
600 * @param t Throwable if transaction commit failed
601 * @param datastore Datastore from which data are read
602 * @param path Path from which data are read
603 * @param result Result of read from {@code datastore}
604 * @param readData Result value which will be set
605 * @param <X> Result type
607 protected final static <X> void handlingCallback(final Throwable t, final LogicalDatastoreType datastore,
608 final YangInstanceIdentifier path, final Optional<X> result,
609 final ReadDataResult<X> readData) {
611 LOG.warn("Exception by reading {} via Restconf: {}", datastore.name(), path, t);
612 throw new RestconfDocumentedException("Problem to get data from transaction.", t);
614 LOG.debug("Reading result data from transaction.");
615 if (result != null) {
616 if (result.isPresent()) {
617 readData.setResult(result.get());
623 public void registerToListenNotification(final NotificationListenerAdapter listener) {
624 checkPreconditions();
626 if (listener.isListening()) {
630 final SchemaPath path = listener.getSchemaPath();
631 final ListenerRegistration<DOMNotificationListener> registration = this.domNotification
632 .registerNotificationListener(listener, path);
634 listener.setRegistration(registration);
637 private final class PATCHStatusContextHelper {
638 PATCHStatusContext status;
640 public PATCHStatusContext getStatus() {
644 public void setStatus(final PATCHStatusContext status) {
645 this.status = status;
649 private void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier normalizedPath,
650 final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) {
651 final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
652 YangInstanceIdentifier rootNormalizedPath = null;
654 final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
656 while (it.hasNext()) {
657 final PathArgument pathArgument = it.next();
658 if (rootNormalizedPath == null) {
659 rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
663 normalizedPathWithoutChildArgs.add(pathArgument);
667 if (normalizedPathWithoutChildArgs.isEmpty()) {
671 Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
673 final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
674 YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
675 rwTx.merge(store, rootNormalizedPath, parentStructure);