Remove the option to deliver streams over WebSockets
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / transactions / MdsalRestconfTransaction.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
9
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;
13
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;
33
34 final class MdsalRestconfTransaction extends RestconfTransaction {
35     private static final Logger LOG = LoggerFactory.getLogger(MdsalRestconfTransaction.class);
36
37     private DOMDataTreeReadWriteTransaction rwTx;
38
39     MdsalRestconfTransaction(final DatabindContext databind, final DOMDataBroker dataBroker) {
40         super(databind);
41         rwTx = dataBroker.newReadWriteTransaction();
42     }
43
44     @Override
45     public void cancel() {
46         if (rwTx != null) {
47             rwTx.cancel();
48             rwTx = null;
49         }
50     }
51
52     @Override
53     void deleteImpl(final YangInstanceIdentifier path) {
54         if (TransactionUtil.syncAccess(verifyNotNull(rwTx).exists(CONFIGURATION, path), path)) {
55             rwTx.delete(CONFIGURATION, path);
56         } else {
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,
59                 path);
60         }
61     }
62
63     @Override
64     void removeImpl(final YangInstanceIdentifier path) {
65         verifyNotNull(rwTx).delete(CONFIGURATION, path);
66     }
67
68     @Override
69     void mergeImpl(final YangInstanceIdentifier path, final NormalizedNode data) {
70         verifyNotNull(rwTx).merge(CONFIGURATION, path, data);
71     }
72
73     @Override
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);
79
80             final var children = ((DistinctNodeContainer<?, ?>) data).body();
81
82             // Fire off an existence check
83             final var check = ExistenceCheck.start(verifyNotNull(rwTx), CONFIGURATION, path, false, children);
84
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);
89             }
90
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,
94                     conflict.path());
95             }
96         } else {
97             RestconfStrategy.checkItemDoesNotExists(verifyNotNull(rwTx).exists(CONFIGURATION, path), path);
98             ensureParentsByMerge(path);
99             verifyNotNull(rwTx).put(CONFIGURATION, path, data);
100         }
101     }
102
103     @Override
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);
109
110             for (var child : ((NormalizedNodeContainer<?>) data).body()) {
111                 final var childPath = path.node(child.name());
112                 verifyNotNull(rwTx).put(CONFIGURATION, childPath, child);
113             }
114         } else {
115             ensureParentsByMerge(path);
116             verifyNotNull(rwTx).put(CONFIGURATION, path, data);
117         }
118     }
119
120     @Override
121     public ListenableFuture<? extends @NonNull CommitInfo> commit() {
122         final var ret = verifyNotNull(rwTx).commit();
123         rwTx = null;
124         return ret;
125     }
126
127     @Override
128     ListenableFuture<Optional<NormalizedNode>> read(final YangInstanceIdentifier path) {
129         return verifyNotNull(rwTx).read(CONFIGURATION, path);
130     }
131
132     @Override
133     NormalizedNodeContainer<?> readList(final YangInstanceIdentifier path) {
134         return (NormalizedNodeContainer<?>) TransactionUtil.syncAccess(read(path), path).orElse(null);
135     }
136 }