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;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.ArrayList;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.common.api.CommitInfo;
18 import org.opendaylight.odlparent.logging.markers.Markers;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
23 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
24 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * A handle to a set of operations being executed atomically on top of some backing store.
31 // FIXME: it seems the first two operations deal with lifecycle of a transaction, while others invoke various
32 // operations. This should be handled through proper allocation indirection.
33 abstract class RestconfTransaction {
34 private static final Logger LOG = LoggerFactory.getLogger(RestconfTransaction.class);
36 final @NonNull EffectiveModelContext modelContext;
38 RestconfTransaction(final EffectiveModelContext modelContext) {
39 this.modelContext = requireNonNull(modelContext);
43 * Rollback changes and unlock the datastore.
45 // FIXME: this looks synchronous, but it should not be
46 abstract void cancel();
49 * Confirm previous operations.
51 * @return a FluentFuture containing the result of the commit information
53 abstract ListenableFuture<? extends @NonNull CommitInfo> commit();
56 * Delete data from the datastore.
58 * @param path the data object path
60 final void delete(final YangInstanceIdentifier path) {
61 LOG.trace("Delete {}", path);
62 deleteImpl(requireNonNull(path));
65 abstract void deleteImpl(@NonNull YangInstanceIdentifier path);
68 * Remove data from the datastore.
70 * @param path the data object path
72 final void remove(final YangInstanceIdentifier path) {
73 LOG.trace("Remove {}", path);
74 removeImpl(requireNonNull(path));
77 abstract void removeImpl(@NonNull YangInstanceIdentifier path);
80 * Merges a piece of data with the existing data at a specified path.
82 * @param path the data object path
83 * @param data the data object to be merged to the specified path
85 final void merge(final YangInstanceIdentifier path, final NormalizedNode data) {
86 LOG.trace("Merge {}", path);
87 LOG.trace(Markers.confidential(), "Merge with {}", data.prettyTree());
88 mergeImpl(requireNonNull(path), data);
91 abstract void mergeImpl(@NonNull YangInstanceIdentifier path, @NonNull NormalizedNode data);
94 * Stores a piece of data at the specified path.
96 * @param path the data object path
97 * @param data the data object to be merged to the specified path
99 final void create(final YangInstanceIdentifier path, final NormalizedNode data) {
100 LOG.trace("Create {}", path);
101 LOG.trace(Markers.confidential(), "Create as {}", data.prettyTree());
102 createImpl(requireNonNull(path), data);
105 abstract void createImpl(@NonNull YangInstanceIdentifier path, @NonNull NormalizedNode data);
108 * Replace a piece of data at the specified path.
110 * @param path the data object path
111 * @param data the data object to be merged to the specified path
113 final void replace(final YangInstanceIdentifier path, final NormalizedNode data) {
114 LOG.trace("Replace {}", path);
115 LOG.trace(Markers.confidential(), "Replace with {}", data.prettyTree());
116 replaceImpl(requireNonNull(path), data);
119 abstract void replaceImpl(@NonNull YangInstanceIdentifier path, @NonNull NormalizedNode data);
121 final @Nullable NormalizedNodeContainer<?> readList(final YangInstanceIdentifier path) {
122 return (NormalizedNodeContainer<?>) TransactionUtil.syncAccess(read(path), path).orElse(null);
125 abstract ListenableFuture<Optional<NormalizedNode>> read(YangInstanceIdentifier path);
128 * Merge parents of data.
130 * @param path path of data
132 // FIXME: this method should only be invoked in MdsalRestconfStrategy, and even then only if we are crossing
134 final void ensureParentsByMerge(final YangInstanceIdentifier path) {
135 final var normalizedPathWithoutChildArgs = new ArrayList<PathArgument>();
136 YangInstanceIdentifier rootNormalizedPath = null;
138 final var it = path.getPathArguments().iterator();
140 while (it.hasNext()) {
141 final var pathArgument = it.next();
142 if (rootNormalizedPath == null) {
143 rootNormalizedPath = YangInstanceIdentifier.of(pathArgument);
147 normalizedPathWithoutChildArgs.add(pathArgument);
151 if (normalizedPathWithoutChildArgs.isEmpty()) {
155 merge(rootNormalizedPath,
156 ImmutableNodes.fromInstanceId(modelContext, YangInstanceIdentifier.of(normalizedPathWithoutChildArgs)));