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