a8eef5a3cae2687f6cc552454407e0bb8bf9eb97
[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 java.util.Collections;
11 import java.util.Map.Entry;
12
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
15 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
16 import org.opendaylight.yangtools.yang.binding.DataObject;
17 import org.opendaylight.yangtools.yang.binding.Identifiable;
18 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import com.google.common.base.Optional;
25 import com.google.common.collect.Iterables;
26 import com.google.common.util.concurrent.CheckedFuture;
27
28 /**
29  *
30  * Abstract Base Transaction for transactions which are backed by
31  * {@link DOMDataWriteTransaction}
32  */
33 public class AbstractWriteTransaction<T extends DOMDataWriteTransaction> extends
34         AbstractForwardedTransaction<T> {
35
36     private static final Logger LOG = LoggerFactory.getLogger(AbstractWriteTransaction.class);
37
38     protected AbstractWriteTransaction(final T delegate,
39             final BindingToNormalizedNodeCodec codec) {
40         super(delegate, codec);
41     }
42
43     protected final void doPut(final LogicalDatastoreType store,
44             final InstanceIdentifier<?> path, final DataObject data) {
45        final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec()
46                 .toNormalizedNode(path, data);
47         ensureListParentIfNeeded(store,path,normalized);
48         getDelegate().put(store, normalized.getKey(), normalized.getValue());
49     }
50
51
52     /**
53      *
54      * Ensures list parent if item is list, otherwise noop.
55      *
56      * <p>
57      * One of properties of binding specification is that it is imposible
58      * to represent list as a whole and thus it is impossible to write
59      * empty variation of MapNode without creating parent node, with
60      * empty list.
61      *
62      * <p>
63      * This actually makes writes such as
64      * <pre>
65      * put("Nodes", new NodesBuilder().build());
66      * put("Nodes/Node[key]", new NodeBuilder().setKey("key").build());
67      * </pre>
68      * To result in three DOM operations:
69      * <pre>
70      * put("/nodes",domNodes);
71      * merge("/nodes/node",domNodeList);
72      * put("/nodes/node/node[key]",domNode);
73      * </pre>
74      *
75      *
76      * In order to allow that to be inserted if necessary, if we know
77      * item is list item, we will try to merge empty MapNode or OrderedNodeMap
78      * to ensure list exists.
79      *
80      * @param store Data Store type
81      * @param path Path to data (Binding Aware)
82      * @param normalized Normalized version of data to be written
83      */
84     private void ensureListParentIfNeeded(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
85             final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalized) {
86         if(Identifiable.class.isAssignableFrom(path.getTargetType())) {
87             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentMapPath = getParent(normalized.getKey()).get();
88             NormalizedNode<?, ?> emptyParent = getCodec().getDefaultNodeFor(parentMapPath);
89             getDelegate().merge(store, parentMapPath, emptyParent);
90         }
91
92     }
93
94     // FIXME (should be probaly part of InstanceIdentifier)
95     protected static Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> getParent(
96             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier child) {
97
98         Iterable<PathArgument> mapEntryItemPath = child.getPathArguments();
99         int parentPathSize = Iterables.size(mapEntryItemPath) - 1;
100         if(parentPathSize > 1) {
101             return Optional.of(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(Iterables.limit(mapEntryItemPath,  parentPathSize)));
102         } else if(parentPathSize == 0) {
103             return Optional.of(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(Collections.<PathArgument>emptyList()));
104         } else {
105             return Optional.absent();
106         }
107     }
108
109     protected final void doMerge(final LogicalDatastoreType store,
110             final InstanceIdentifier<?> path, final DataObject data) {
111
112         final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec()
113                 .toNormalizedNode(path, data);
114         ensureListParentIfNeeded(store,path,normalized);
115         getDelegate().merge(store, normalized.getKey(), normalized.getValue());
116     }
117
118     protected final void doDelete(final LogicalDatastoreType store,
119             final InstanceIdentifier<?> path) {
120         final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = getCodec().toNormalized(path);
121         getDelegate().delete(store, normalized);
122     }
123
124     protected final CheckedFuture<Void,TransactionCommitFailedException> doSubmit() {
125         return getDelegate().submit();
126     }
127
128     protected final boolean doCancel() {
129         return getDelegate().cancel();
130     }
131
132 }