2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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.restconf.nb.rfc8040.rests.transactions;
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
12 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.fromInstanceId;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.util.Optional;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.mdsal.common.api.CommitInfo;
18 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
19 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
20 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
21 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.ExistenceCheck.Conflict;
22 import org.opendaylight.restconf.server.api.DatabindContext;
23 import org.opendaylight.yangtools.yang.common.ErrorTag;
24 import org.opendaylight.yangtools.yang.common.ErrorType;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 final class MdsalRestconfTransaction extends RestconfTransaction {
35 private static final Logger LOG = LoggerFactory.getLogger(MdsalRestconfTransaction.class);
37 private DOMDataTreeReadWriteTransaction rwTx;
39 MdsalRestconfTransaction(final DatabindContext databind, final DOMDataBroker dataBroker) {
41 rwTx = dataBroker.newReadWriteTransaction();
45 public void cancel() {
53 void deleteImpl(final YangInstanceIdentifier path) {
54 if (TransactionUtil.syncAccess(verifyNotNull(rwTx).exists(CONFIGURATION, path), path)) {
55 rwTx.delete(CONFIGURATION, path);
57 LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
58 throw new RestconfDocumentedException("Data does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
64 void removeImpl(final YangInstanceIdentifier path) {
65 verifyNotNull(rwTx).delete(CONFIGURATION, path);
69 void mergeImpl(final YangInstanceIdentifier path, final NormalizedNode data) {
70 verifyNotNull(rwTx).merge(CONFIGURATION, path, data);
74 void createImpl(final YangInstanceIdentifier path, final NormalizedNode data) {
75 if (data instanceof MapNode || data instanceof LeafSetNode) {
76 final var emptySubTree = fromInstanceId(databind.modelContext(), path);
77 merge(YangInstanceIdentifier.of(emptySubTree.name()), emptySubTree);
78 ensureParentsByMerge(path);
80 final var children = ((DistinctNodeContainer<?, ?>) data).body();
82 // Fire off an existence check
83 final var check = ExistenceCheck.start(verifyNotNull(rwTx), CONFIGURATION, path, false, children);
85 // ... and perform any put() operations, which happen-after existence check
86 for (var child : children) {
87 final var childPath = path.node(child.name());
88 verifyNotNull(rwTx).put(CONFIGURATION, childPath, child);
91 // ... finally collect existence checks and abort the transaction if any of them failed.
92 if (check.getOrThrow() instanceof Conflict conflict) {
93 throw new RestconfDocumentedException("Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS,
97 RestconfStrategy.checkItemDoesNotExists(verifyNotNull(rwTx).exists(CONFIGURATION, path), path);
98 ensureParentsByMerge(path);
99 verifyNotNull(rwTx).put(CONFIGURATION, path, data);
104 void replaceImpl(final YangInstanceIdentifier path, final NormalizedNode data) {
105 if (data instanceof MapNode || data instanceof LeafSetNode) {
106 final var emptySubtree = fromInstanceId(databind.modelContext(), path);
107 merge(YangInstanceIdentifier.of(emptySubtree.name()), emptySubtree);
108 ensureParentsByMerge(path);
110 for (var child : ((NormalizedNodeContainer<?>) data).body()) {
111 final var childPath = path.node(child.name());
112 verifyNotNull(rwTx).put(CONFIGURATION, childPath, child);
115 ensureParentsByMerge(path);
116 verifyNotNull(rwTx).put(CONFIGURATION, path, data);
121 public ListenableFuture<? extends @NonNull CommitInfo> commit() {
122 final var ret = verifyNotNull(rwTx).commit();
128 ListenableFuture<Optional<NormalizedNode>> read(final YangInstanceIdentifier path) {
129 return verifyNotNull(rwTx).read(CONFIGURATION, path);
133 NormalizedNodeContainer<?> readList(final YangInstanceIdentifier path) {
134 return (NormalizedNodeContainer<?>) TransactionUtil.syncAccess(read(path), path).orElse(null);