Merge "Prevent ConfigPusher from killing its thread"
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / NetconfDeviceTwoPhaseCommitTransaction.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.sal.connect.netconf;
9
10 import java.util.Collections;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Map.Entry;
14 import java.util.Set;
15
16 import org.eclipse.xtext.xbase.lib.IterableExtensions;
17 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
18 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.common.RpcResult;
21 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
22 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
24 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
25 import org.opendaylight.yangtools.yang.data.api.Node;
26 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
27 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
28
29 import com.google.common.base.Optional;
30 import com.google.common.base.Preconditions;
31 import com.google.common.collect.Collections2;
32 import com.google.common.collect.ImmutableList;
33 import com.google.common.collect.Iterables;
34 import com.google.common.collect.Lists;
35
36 import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*;
37
38 public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
39
40     private NetconfDevice device;
41     private final DataModification<InstanceIdentifier, CompositeNode> modification;
42     private boolean candidateSupported = true;
43
44     public NetconfDeviceTwoPhaseCommitTransaction(NetconfDevice device,
45             DataModification<InstanceIdentifier, CompositeNode> modification) {
46         super();
47         this.device = device;
48         this.modification = modification;
49     }
50
51     public void prepare() {
52         for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
53             sendRemove(toRemove);
54         }
55         for(Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
56             sendMerge(toUpdate.getKey(),toUpdate.getValue());
57         }
58
59     }
60
61     private void sendMerge(InstanceIdentifier key, CompositeNode value) {
62         sendEditRpc(createEditStructure(key, Optional.<String>absent(), Optional.of(value)));
63     }
64
65     private void sendRemove(InstanceIdentifier toRemove) {
66         sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional.<CompositeNode> absent()));
67     }
68
69     private void sendEditRpc(CompositeNode editStructure) {
70         CompositeNodeBuilder<ImmutableCompositeNode> builder = configurationRpcBuilder();
71         builder.setQName(NETCONF_EDIT_CONFIG_QNAME);
72         builder.add(editStructure);
73         
74         RpcResult<CompositeNode> rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance());
75         Preconditions.checkState(rpcResult.isSuccessful(),"Rpc Result was unsuccessful");
76         
77     }
78
79     private CompositeNodeBuilder<ImmutableCompositeNode> configurationRpcBuilder() {
80         CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
81         
82         Node<?> targetNode;
83         if(candidateSupported) {
84             targetNode = ImmutableCompositeNode.create(NETCONF_CANDIDATE_QNAME, ImmutableList.<Node<?>>of());
85         } else {
86             targetNode = ImmutableCompositeNode.create(NETCONF_RUNNING_QNAME, ImmutableList.<Node<?>>of());
87         }
88         Node<?> targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.<Node<?>>of(targetNode));
89         ret.add(targetWrapperNode);
90         return ret;
91     }
92
93     private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> action,
94             Optional<CompositeNode> lastChildOverride) {
95         List<PathArgument> path = dataPath.getPath();
96         List<PathArgument> reversed = Lists.reverse(path);
97         CompositeNode previous = null;
98         boolean isLast = true;
99         for (PathArgument arg : reversed) {
100             CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
101             builder.setQName(arg.getNodeType());
102             Map<QName, Object> predicates = Collections.emptyMap();
103             if (arg instanceof NodeIdentifierWithPredicates) {
104                 predicates = ((NodeIdentifierWithPredicates) arg).getKeyValues();
105             }
106             for (Entry<QName, Object> entry : predicates.entrySet()) {
107                 builder.addLeaf(entry.getKey(), entry.getValue());
108             }
109             
110             if (isLast) {
111                 if (action.isPresent()) {
112                     builder.setAttribute(NETCONF_ACTION_QNAME, action.get());
113                 }
114                 if (lastChildOverride.isPresent()) {
115                     List<Node<?>> children = lastChildOverride.get().getChildren();
116                     for(Node<?> child : children) {
117                         if(!predicates.containsKey(child.getKey())) {
118                             builder.add(child);
119                         }
120                     }
121                     
122                 }
123             } else {
124                 builder.add(previous);
125             }
126             previous = builder.toInstance();
127             isLast = false;
128         }
129         return ImmutableCompositeNode.create(NETCONF_CONFIG_QNAME, ImmutableList.<Node<?>>of(previous));
130     }
131
132     @Override
133     public RpcResult<Void> finish() throws IllegalStateException {
134         CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
135         commitInput.setQName(NETCONF_COMMIT_QNAME);
136         RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance());
137         return (RpcResult<Void>) rpcResult;
138     }
139
140     @Override
141     public DataModification<InstanceIdentifier, CompositeNode> getModification() {
142         return this.modification;
143     }
144
145     @Override
146     public RpcResult<Void> rollback() throws IllegalStateException {
147         // TODO Auto-generated method stub
148         return null;
149     }
150 }