Default AsyncWriteTransaction#submit()
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / AbstractWriteTransaction.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 com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FluentFuture;
13 import java.util.Map.Entry;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.opendaylight.mdsal.common.api.CommitInfo;
16 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
17 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
18 import org.opendaylight.yangtools.yang.binding.DataObject;
19 import org.opendaylight.yangtools.yang.binding.Identifiable;
20 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
23
24 /**
25  * Abstract Base Transaction for transactions which are backed by
26  * {@link DOMDataTreeWriteTransaction}.
27  */
28 public abstract class AbstractWriteTransaction<T extends DOMDataTreeWriteTransaction> extends
29         AbstractForwardedTransaction<T> {
30
31     protected AbstractWriteTransaction(final T delegate, final BindingToNormalizedNodeCodec codec) {
32         super(delegate, codec);
33     }
34
35     public final <U extends DataObject> void put(final LogicalDatastoreType store,
36             final InstanceIdentifier<U> path, final U data, final boolean createParents) {
37         Preconditions.checkArgument(!path.isWildcarded(), "Cannot put data into wildcarded path %s", path);
38
39         final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
40         if (createParents) {
41             ensureParentsByMerge(store, normalized.getKey(), path);
42         } else {
43             ensureListParentIfNeeded(store,path,normalized);
44         }
45
46         getDelegate().put(store, normalized.getKey(), normalized.getValue());
47     }
48
49     public final <U extends DataObject> void merge(final LogicalDatastoreType store,
50             final InstanceIdentifier<U> path, final U data,final boolean createParents) {
51         Preconditions.checkArgument(!path.isWildcarded(), "Cannot merge data into wildcarded path %s", path);
52
53         final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
54         if (createParents) {
55             ensureParentsByMerge(store, normalized.getKey(), path);
56         } else {
57             ensureListParentIfNeeded(store,path,normalized);
58         }
59
60         getDelegate().merge(store, normalized.getKey(), normalized.getValue());
61     }
62
63     /**
64      * Ensures list parent if item is list, otherwise noop.
65      *
66      * <p>
67      * One of properties of binding specification is that it is imposible
68      * to represent list as a whole and thus it is impossible to write
69      * empty variation of MapNode without creating parent node, with
70      * empty list.
71      *
72      * <p>
73      * This actually makes writes such as
74      * <pre>
75      * put("Nodes", new NodesBuilder().build());
76      * put("Nodes/Node[key]", new NodeBuilder().setKey("key").build());
77      * </pre>
78      * To result in three DOM operations:
79      * <pre>
80      * put("/nodes",domNodes);
81      * merge("/nodes/node",domNodeList);
82      * put("/nodes/node/node[key]",domNode);
83      * </pre>
84      *
85      * <p>
86      * In order to allow that to be inserted if necessary, if we know
87      * item is list item, we will try to merge empty MapNode or OrderedNodeMap
88      * to ensure list exists.
89      *
90      * @param store Data Store type
91      * @param path Path to data (Binding Aware)
92      * @param normalized Normalized version of data to be written
93      */
94     private void ensureListParentIfNeeded(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
95             final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized) {
96         if (Identifiable.class.isAssignableFrom(path.getTargetType())) {
97             final YangInstanceIdentifier parentMapPath = normalized.getKey().getParent();
98             Preconditions.checkArgument(parentMapPath != null, "Map path %s does not have a parent", path);
99
100             final NormalizedNode<?, ?> emptyParent = getCodec().getDefaultNodeFor(parentMapPath);
101             getDelegate().merge(store, parentMapPath, emptyParent);
102         }
103     }
104
105     /**
106      * Use {@link YangInstanceIdentifier#getParent()} instead.
107      */
108     @Deprecated
109     protected static Optional<YangInstanceIdentifier> getParent(final YangInstanceIdentifier child) {
110         return Optional.fromNullable(child.getParent());
111     }
112
113     /**
114      * Subclasses of this class are required to implement creation of parent nodes based on
115      * behaviour of their underlying transaction.
116      *
117      * @param store an instance of LogicalDatastoreType
118      * @param domPath an instance of YangInstanceIdentifier
119      * @param path an instance of InstanceIdentifier
120      */
121     protected final void ensureParentsByMerge(final LogicalDatastoreType store, final YangInstanceIdentifier domPath,
122             final InstanceIdentifier<?> path) {
123         final YangInstanceIdentifier parentPath = domPath.getParent();
124         if (parentPath != null) {
125             final NormalizedNode<?, ?> parentNode = getCodec().instanceIdentifierToNode(parentPath);
126             getDelegate().merge(store, YangInstanceIdentifier.create(parentNode.getIdentifier()), parentNode);
127         }
128     }
129
130     protected final void doDelete(final LogicalDatastoreType store,
131             final InstanceIdentifier<?> path) {
132         Preconditions.checkArgument(!path.isWildcarded(), "Cannot delete wildcarded path %s", path);
133
134         final YangInstanceIdentifier normalized = getCodec().toYangInstanceIdentifierBlocking(path);
135         getDelegate().delete(store, normalized);
136     }
137
138     protected final @NonNull FluentFuture<? extends @NonNull CommitInfo> doCommit() {
139         return getDelegate().commit();
140     }
141
142     protected final boolean doCancel() {
143         return getDelegate().cancel();
144     }
145
146 }