2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.md.sal.binding.impl;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Iterables;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import java.util.Collections;
15 import java.util.Map.Entry;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
18 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
19 import org.opendaylight.yangtools.yang.binding.DataObject;
20 import org.opendaylight.yangtools.yang.binding.Identifiable;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 * Abstract Base Transaction for transactions which are backed by
29 * {@link DOMDataWriteTransaction}
31 public abstract class AbstractWriteTransaction<T extends DOMDataWriteTransaction> extends
32 AbstractForwardedTransaction<T> {
34 protected AbstractWriteTransaction(final T delegate, final BindingToNormalizedNodeCodec codec) {
35 super(delegate, codec);
38 public final <U extends DataObject> void put(final LogicalDatastoreType store,
39 final InstanceIdentifier<U> path, final U data, final boolean createParents) {
40 Preconditions.checkArgument(!path.isWildcarded(), "Cannot put data into wildcarded path %s", path);
42 final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
44 ensureParentsByMerge(store, normalized.getKey(), path);
46 ensureListParentIfNeeded(store,path,normalized);
49 getDelegate().put(store, normalized.getKey(), normalized.getValue());
52 public final <U extends DataObject> void merge(final LogicalDatastoreType store,
53 final InstanceIdentifier<U> path, final U data,final boolean createParents) {
54 Preconditions.checkArgument(!path.isWildcarded(), "Cannot merge data into wildcarded path %s", path);
56 final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = getCodec().toNormalizedNode(path, data);
58 ensureParentsByMerge(store, normalized.getKey(), path);
60 ensureListParentIfNeeded(store,path,normalized);
63 getDelegate().merge(store, normalized.getKey(), normalized.getValue());
68 * Ensures list parent if item is list, otherwise noop.
71 * One of properties of binding specification is that it is imposible
72 * to represent list as a whole and thus it is impossible to write
73 * empty variation of MapNode without creating parent node, with
77 * This actually makes writes such as
79 * put("Nodes", new NodesBuilder().build());
80 * put("Nodes/Node[key]", new NodeBuilder().setKey("key").build());
82 * To result in three DOM operations:
84 * put("/nodes",domNodes);
85 * merge("/nodes/node",domNodeList);
86 * put("/nodes/node/node[key]",domNode);
90 * In order to allow that to be inserted if necessary, if we know
91 * item is list item, we will try to merge empty MapNode or OrderedNodeMap
92 * to ensure list exists.
94 * @param store Data Store type
95 * @param path Path to data (Binding Aware)
96 * @param normalized Normalized version of data to be written
98 private void ensureListParentIfNeeded(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
99 final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized) {
100 if (Identifiable.class.isAssignableFrom(path.getTargetType())) {
101 YangInstanceIdentifier parentMapPath = getParent(normalized.getKey()).get();
102 NormalizedNode<?, ?> emptyParent = getCodec().getDefaultNodeFor(parentMapPath);
103 getDelegate().merge(store, parentMapPath, emptyParent);
107 // FIXME (should be probaly part of InstanceIdentifier)
108 protected static Optional<YangInstanceIdentifier> getParent(
109 final YangInstanceIdentifier child) {
111 Iterable<PathArgument> mapEntryItemPath = child.getPathArguments();
112 int parentPathSize = Iterables.size(mapEntryItemPath) - 1;
113 if (parentPathSize > 1) {
114 return Optional.of(YangInstanceIdentifier.create(Iterables.limit(mapEntryItemPath, parentPathSize)));
115 } else if(parentPathSize == 0) {
116 return Optional.of(YangInstanceIdentifier.create(Collections.<PathArgument>emptyList()));
118 return Optional.absent();
123 * Subclasses of this class are required to implement creation of parent
124 * nodes based on behaviour of their underlying transaction.
130 protected abstract void ensureParentsByMerge(LogicalDatastoreType store,
131 YangInstanceIdentifier key, InstanceIdentifier<?> path);
133 protected final void doDelete(final LogicalDatastoreType store,
134 final InstanceIdentifier<?> path) {
135 Preconditions.checkArgument(!path.isWildcarded(), "Cannot delete wildcarded path %s", path);
137 final YangInstanceIdentifier normalized = getCodec().toNormalized(path);
138 getDelegate().delete(store, normalized);
141 protected final CheckedFuture<Void,TransactionCommitFailedException> doSubmit() {
142 return getDelegate().submit();
145 protected final boolean doCancel() {
146 return getDelegate().cancel();