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