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 java.util.Objects.requireNonNull;
11 import static org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil.DELETE_TX_TYPE;
12 import static org.opendaylight.restconf.nb.rfc8040.rests.utils.PostDataTransactionUtil.checkItemDoesNotExists;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.Collection;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.mdsal.common.api.CommitInfo;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.mdsal.common.api.ReadFailedException;
23 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
26 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
27 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
28 import org.opendaylight.restconf.common.errors.RestconfError;
29 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
30 import org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil;
31 import org.opendaylight.restconf.nb.rfc8040.rests.utils.TransactionUtil;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 * Implementation of RESTCONF operations using {@link DOMTransactionChain} and related concepts.
43 * @see DOMTransactionChain
44 * @see DOMDataTreeReadWriteTransaction
46 public final class MdsalRestconfStrategy extends RestconfStrategy {
47 private final DOMTransactionChain transactionChain;
48 private final TransactionChainHandler transactionChainHandler;
50 private DOMDataTreeReadWriteTransaction rwTx;
52 public MdsalRestconfStrategy(final DOMDataBroker dataBroker) {
53 this(new TransactionChainHandler(dataBroker));
56 public MdsalRestconfStrategy(final TransactionChainHandler transactionChainHandler) {
57 this.transactionChainHandler = requireNonNull(transactionChainHandler);
58 transactionChain = transactionChainHandler.get();
62 public void prepareReadWriteExecution() {
63 rwTx = transactionChain.newReadWriteTransaction();
67 public void cancel() {
71 transactionChain.close();
75 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
76 final YangInstanceIdentifier path) {
78 return rwTx.read(store, path);
80 try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
81 return tx.read(store, path);
87 public FluentFuture<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
88 return rwTx.exists(store, path);
92 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
93 DeleteDataTransactionUtil.checkItemExists(this, LogicalDatastoreType.CONFIGURATION, path,
95 rwTx.delete(store, path);
99 public void remove(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
100 rwTx.delete(store, path);
104 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
105 final NormalizedNode<?, ?> data) {
106 rwTx.merge(store, path, data);
110 public void create(final LogicalDatastoreType store, final YangInstanceIdentifier path,
111 final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
112 if (data instanceof MapNode || data instanceof LeafSetNode) {
113 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
114 merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
116 TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
118 final Collection<? extends NormalizedNode<?, ?>> children =
119 ((NormalizedNodeContainer<?, ?, ?>) data).getValue();
120 final BatchedExistenceCheck check =
121 BatchedExistenceCheck.start(this, LogicalDatastoreType.CONFIGURATION, path, children);
123 for (final NormalizedNode<?, ?> child : children) {
124 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
125 rwTx.put(store, childPath, child);
128 // ... finally collect existence checks and abort the transaction if any of them failed.
129 checkExistence(path, check);
131 checkItemDoesNotExists(this, LogicalDatastoreType.CONFIGURATION, path);
132 TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
133 rwTx.put(store, path, data);
138 public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
139 final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
140 if (data instanceof MapNode || data instanceof LeafSetNode) {
141 final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
142 merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
144 TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
146 for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
147 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
148 rwTx.put(store, childPath, child);
151 TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
152 rwTx.put(store, path, data);
157 public FluentFuture<? extends @NonNull CommitInfo> commit() {
158 return rwTx.commit();
162 public DOMTransactionChain getTransactionChain() {
163 return transactionChain;
167 public TransactionChainHandler getTransactionChainHandler() {
168 return transactionChainHandler;
171 private static void checkExistence(final YangInstanceIdentifier path, final BatchedExistenceCheck check) {
172 final Map.Entry<YangInstanceIdentifier, ReadFailedException> failure;
174 failure = check.getFailure();
175 } catch (InterruptedException e) {
176 throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
179 if (failure != null) {
180 final ReadFailedException e = failure.getValue();
182 throw new RestconfDocumentedException("Data already exists",
183 RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.DATA_EXISTS, failure.getKey());
186 throw new RestconfDocumentedException(
187 "Could not determine the existence of path " + failure.getKey(), e, e.getErrorList());