Bug 6714 - Use singleton service in clustered netconf topology
[netconf.git] / netconf / netconf-topology / src / main / java / org / opendaylight / netconf / topology / impl / TopologyNodeWriter.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.netconf.topology.impl;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.util.concurrent.locks.ReentrantLock;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.netconf.topology.util.NodeWriter;
26 import org.opendaylight.netconf.topology.util.TopologyUtil;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class TopologyNodeWriter implements NodeWriter{
42
43     private static final Logger LOG = LoggerFactory.getLogger(TopologyNodeWriter.class);
44
45     private final String topologyId;
46     private final BindingTransactionChain txChain;
47
48     private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
49     private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
50
51     private final ReentrantLock lock = new ReentrantLock(true);
52
53     public TopologyNodeWriter(final String topologyId, final DataBroker dataBroker) {
54         this.topologyId = topologyId;
55         this.txChain = Preconditions.checkNotNull(dataBroker).createTransactionChain(new TransactionChainListener() {
56             @Override
57             public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
58                 LOG.error("{}: TransactionChain({}) {} FAILED!", chain,
59                         transaction.getIdentifier(), cause);
60                 throw new IllegalStateException("Clustered topology writer TransactionChain(" + chain + ") not committed correctly", cause);
61             }
62
63             @Override
64             public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
65                 LOG.trace("Clustered topology writer TransactionChain({}) SUCCESSFUL", chain);
66             }
67         });
68
69         this.networkTopologyPath = InstanceIdentifier.builder(NetworkTopology.class).build();
70         this.topologyListPath = networkTopologyPath.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
71
72         // write an empty topology container at the start
73         final WriteTransaction wTx = txChain.newWriteOnlyTransaction();
74         createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.OPERATIONAL);
75         createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.CONFIGURATION);
76         commitTransaction(wTx, "init topology container", new NodeId("topology-netconf"));
77     }
78
79     @Override
80     public void init(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
81         lock.lock();
82         try {
83             final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
84
85             createNetworkTopologyIfNotPresent(writeTx, LogicalDatastoreType.OPERATIONAL);
86             final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
87
88             LOG.trace("{}: Init device state transaction {} putting if absent operational data started. Putting data on path {}",
89                     id.getValue(), writeTx.getIdentifier(), path);
90             writeTx.put(LogicalDatastoreType.OPERATIONAL, path, operationalDataNode);
91             LOG.trace("{}: Init device state transaction {} putting operational data ended.",
92                     id.getValue(), writeTx.getIdentifier());
93
94             commitTransaction(writeTx, "init", id);
95         } finally {
96             lock.unlock();
97         }
98     }
99
100     @Override
101     public void update(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
102         lock.lock();
103         try {
104             final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
105
106             final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
107             LOG.trace("{}: Update device state transaction {} merging operational data started. Putting data on path {}",
108                     id, writeTx.getIdentifier(), operationalDataNode);
109             writeTx.put(LogicalDatastoreType.OPERATIONAL, path, operationalDataNode);
110             LOG.trace("{}: Update device state transaction {} merging operational data ended.",
111                     id, writeTx.getIdentifier());
112
113             commitTransaction(writeTx, "update", id);
114         } finally {
115             lock.unlock();
116         }
117
118     }
119
120     @Override
121     public void delete(@Nonnull NodeId id) {
122         lock.lock();
123         try {
124             final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
125
126             final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
127
128             LOG.trace(
129                     "{}: Close device state transaction {} removing all data started. Path: {}",
130                     id, writeTx.getIdentifier(), path);
131             writeTx.delete(LogicalDatastoreType.OPERATIONAL, path);
132             LOG.trace(
133                     "{}: Close device state transaction {} removing all data ended.",
134                     id, writeTx.getIdentifier());
135
136             commitTransaction(writeTx, "close", id);
137         } finally {
138             lock.unlock();
139         }
140     }
141
142     private void commitTransaction(final WriteTransaction transaction, final String txType, final NodeId id) {
143         LOG.trace("{}: Committing Transaction {}:{}", id.getValue(), txType,
144                 transaction.getIdentifier());
145         final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
146
147         Futures.addCallback(result, new FutureCallback<Void>() {
148             @Override
149             public void onSuccess(final Void result) {
150                 LOG.trace("{}: Transaction({}) {} SUCCESSFUL", id.getValue(), txType,
151                         transaction.getIdentifier());
152             }
153
154             @Override
155             public void onFailure(final Throwable t) {
156                 LOG.error("{}: Transaction({}) {} FAILED!", id.getValue(), txType,
157                         transaction.getIdentifier(), t);
158                 throw new IllegalStateException(id.getValue() + "  Transaction(" + txType + ") not committed correctly", t);
159             }
160         });
161     }
162
163     private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx, final LogicalDatastoreType datastoreType) {
164
165         final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
166         LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
167                 NetworkTopology.QNAME, writeTx.getIdentifier());
168         writeTx.merge(datastoreType, networkTopologyPath, networkTopology);
169
170         final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
171         LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
172                 Topology.QNAME, writeTx.getIdentifier());
173         writeTx.merge(datastoreType, topologyListPath, topology);
174     }
175 }