742ba5c927eb6a53ccc3123726026c35c9ddf526
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / BindingDOMWriteTransactionAdapter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.mdsal.binding.dom.adapter;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.base.VerifyException;
13 import com.google.common.util.concurrent.FluentFuture;
14 import java.util.HashSet;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.mdsal.binding.api.WriteTransaction;
17 import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode;
18 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer.AugmentationResult;
19 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer.NodeResult;
20 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer.NormalizedResult;
21 import org.opendaylight.mdsal.common.api.CommitInfo;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28
29 class BindingDOMWriteTransactionAdapter<T extends DOMDataTreeWriteTransaction> extends AbstractForwardedTransaction<T>
30         implements WriteTransaction {
31     BindingDOMWriteTransactionAdapter(final AdapterContext adapterContext, final T delegateTx) {
32         super(adapterContext, delegateTx);
33     }
34
35     @Override
36     public final <U extends DataObject> void put(final LogicalDatastoreType store, final InstanceIdentifier<U> path,
37             final U data) {
38         put(store, toNormalized("put", path, data));
39     }
40
41     private void put(final LogicalDatastoreType store, final NormalizedResult normalized) {
42         final var delegate = getDelegate();
43         final var domPath = normalized.path();
44
45         if (normalized instanceof AugmentationResult augment) {
46             // Augmentation: put() child nodes provided with augmentation, delete() those having no data
47             final var putIds = new HashSet<YangInstanceIdentifier.PathArgument>();
48             for (var child : augment.children()) {
49                 final var childId = child.name();
50                 delegate.put(store, domPath.node(childId), child);
51                 putIds.add(childId);
52             }
53             for (var childId : augment.possibleChildren()) {
54                 if (!putIds.contains(childId)) {
55                     delegate.delete(store, domPath.node(childId));
56                 }
57             }
58         } else if (normalized instanceof NodeResult node) {
59             delegate.put(store, domPath, node.node());
60         } else {
61             throw new VerifyException("Unhandled result " + normalized);
62         }
63     }
64
65     @Deprecated
66     @Override
67     public final <U extends DataObject> void mergeParentStructurePut(final LogicalDatastoreType store,
68             final InstanceIdentifier<U> path, final U data) {
69         final var serializer = adapterContext().currentSerializer();
70         final var normalized = toNormalized(serializer, "put", path, data);
71         ensureParentsByMerge(serializer, store, normalized);
72         put(store, normalized);
73     }
74
75     @Override
76     public final <D extends DataObject> void merge(final LogicalDatastoreType store, final InstanceIdentifier<D> path,
77             final D data) {
78         merge(store, toNormalized("merge", path, data));
79     }
80
81     private void merge(final LogicalDatastoreType store, final NormalizedResult normalized) {
82         final var delegate = getDelegate();
83         final var domPath = normalized.path();
84
85         if (normalized instanceof AugmentationResult augment) {
86             // Augmentation: merge individual children
87             for (var child : augment.children()) {
88                 delegate.merge(store, domPath.node(child.name()), child);
89             }
90         } else if (normalized instanceof NodeResult node) {
91             delegate.merge(store, domPath, node.node());
92         } else {
93             throw new VerifyException("Unhandled result " + normalized);
94         }
95     }
96
97     @Deprecated
98     @Override
99     public final <U extends DataObject> void mergeParentStructureMerge(final LogicalDatastoreType store,
100             final InstanceIdentifier<U> path, final U data) {
101         final var serializer = adapterContext().currentSerializer();
102         final var normalized = toNormalized(serializer, "merge", path, data);
103         ensureParentsByMerge(serializer, store, normalized);
104         merge(store, normalized);
105     }
106
107     @Override
108     public final void delete(final LogicalDatastoreType store, final InstanceIdentifier<?> path) {
109         checkArgument(!path.isWildcarded(), "Cannot delete wildcarded path %s", path);
110         final var serializer = adapterContext().currentSerializer();
111
112         // Lookup the codec and the corresponding path
113         final var codecWithPath = serializer.getSubtreeCodecWithPath(path);
114         final var domPath = codecWithPath.path();
115         final var delegate = getDelegate();
116         if (codecWithPath.codec() instanceof BindingAugmentationCodecTreeNode<?> augmentCodec) {
117             // Deletion of an augmentation: issue a delete on all potential children of the augmentation
118             for (var childPath : augmentCodec.childPathArguments()) {
119                 delegate.delete(store, domPath.node(childPath));
120             }
121         } else {
122             delegate.delete(store, domPath);
123         }
124     }
125
126     @Override
127     public FluentFuture<? extends CommitInfo> commit() {
128         return getDelegate().commit();
129     }
130
131     @Override
132     public final boolean cancel() {
133         return getDelegate().cancel();
134     }
135
136     /**
137      * Subclasses of this class are required to implement creation of parent nodes based on behaviour of their
138      * underlying transaction.
139      *
140      * @param serializer Current serializer
141      * @param store an instance of LogicalDatastoreType
142      * @param normalized NormalizedResult of the operation
143      */
144     private void ensureParentsByMerge(final CurrentAdapterSerializer serializer, final LogicalDatastoreType store,
145             final NormalizedResult normalized) {
146         final var path = normalized.path();
147         // AugmentationResult already points to parent path
148         final var parentPath = normalized instanceof AugmentationResult ? path : path.getParent();
149         if (parentPath != null && !parentPath.isEmpty()) {
150             final var parentNode = ImmutableNodes.fromInstanceId(
151                 serializer.getRuntimeContext().getEffectiveModelContext(), parentPath);
152             getDelegate().merge(store, YangInstanceIdentifier.of(parentNode.name()), parentNode);
153         }
154     }
155
156     private <U extends DataObject> @NonNull NormalizedResult toNormalized(final String operation,
157             final InstanceIdentifier<U> path, final U data) {
158         return toNormalized(adapterContext().currentSerializer(), operation, path, data);
159     }
160
161     private static <U extends DataObject> @NonNull NormalizedResult toNormalized(
162             final CurrentAdapterSerializer serializer, final String operation, final InstanceIdentifier<U> path,
163             final U data) {
164         checkArgument(!path.isWildcarded(), "Cannot %s data into wildcarded path %s", operation, path);
165         return serializer.toNormalizedNode(path, data);
166     }
167 }