Turn TransactionInvokerImpl into a component
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepSouthboundProvider.java
1 /*
2  * Copyright © 2015, 2017 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
9
10 import com.google.common.util.concurrent.FluentFuture;
11 import java.util.Collection;
12 import java.util.Map;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.TimeUnit;
15 import java.util.concurrent.atomic.AtomicBoolean;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
24 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
27 import org.opendaylight.mdsal.eos.binding.api.Entity;
28 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
29 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
30 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListener;
31 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
32 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
33 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
34 import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.configuration.HwvtepReconciliationManager;
35 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
36 import org.opendaylight.ovsdb.lib.OvsdbConnection;
37 import org.opendaylight.ovsdb.utils.mdsal.utils.Scheduler;
38 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionHistory;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
44 import org.opendaylight.yangtools.concepts.ListenerRegistration;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.osgi.service.component.annotations.Activate;
47 import org.osgi.service.component.annotations.Component;
48 import org.osgi.service.component.annotations.Deactivate;
49 import org.osgi.service.component.annotations.Reference;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 @Singleton
54 @Component(service = HwvtepSouthboundProviderInfo.class)
55 public final class HwvtepSouthboundProvider
56         implements HwvtepSouthboundProviderInfo, ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
57
58     private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
59     private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
60
61     private final DataBroker dataBroker;
62     private final EntityOwnershipService entityOwnershipService;
63     private final OvsdbConnection ovsdbConnection;
64
65     private HwvtepConnectionManager cm;
66     private EntityOwnershipCandidateRegistration registration;
67     private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
68     private HwvtepDataChangeListener hwvtepDTListener;
69     private HwvtepReconciliationManager hwvtepReconciliationManager;
70     private final AtomicBoolean registered = new AtomicBoolean(false);
71     private ListenerRegistration<HwvtepSouthboundProvider> operTopologyRegistration;
72
73     @Inject
74     @Activate
75     public HwvtepSouthboundProvider(@Reference final DataBroker dataBroker,
76             @Reference final EntityOwnershipService entityOwnership,
77             @Reference final OvsdbConnection ovsdbConnection, @Reference final DOMSchemaService schemaService,
78             @Reference final BindingNormalizedNodeSerializer serializer,
79             @Reference final TransactionInvoker txInvoker) {
80         this.dataBroker = dataBroker;
81         entityOwnershipService = entityOwnership;
82         registration = null;
83         this.ovsdbConnection = ovsdbConnection;
84         // FIXME: eliminate this static wiring
85         HwvtepSouthboundUtil.setInstanceIdentifierCodec(new InstanceIdentifierCodec(schemaService, serializer));
86         LOG.info("HwvtepSouthboundProvider ovsdbConnectionService: {}", ovsdbConnection);
87         cm = new HwvtepConnectionManager(dataBroker, txInvoker, entityOwnershipService, ovsdbConnection);
88         hwvtepDTListener = new HwvtepDataChangeListener(dataBroker, cm);
89         hwvtepReconciliationManager = new HwvtepReconciliationManager(dataBroker, cm);
90         //Register listener for entityOnwership changes
91         providerOwnershipChangeListener =
92                 new HwvtepsbPluginInstanceEntityOwnershipListener(this,entityOwnershipService);
93
94         //register instance entity to get the ownership of the provider
95         Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
96         try {
97             registration = entityOwnershipService.registerCandidate(instanceEntity);
98         } catch (CandidateAlreadyRegisteredException e) {
99             LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
100                     + "registered for ownership", instanceEntity, e);
101         }
102         InstanceIdentifier<Topology> path = InstanceIdentifier
103                 .create(NetworkTopology.class)
104                 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
105         DataTreeIdentifier<Topology> treeId =
106                 DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, path);
107
108         LOG.trace("Registering listener for path {}", treeId);
109         operTopologyRegistration = dataBroker.registerDataTreeChangeListener(treeId, this);
110         Scheduler.getScheduledExecutorService().schedule(() -> {
111             if (!registered.get()) {
112                 openOvsdbPort();
113                 LOG.error("Timed out to get eos notification opening the port now");
114             }
115         }, HwvtepSouthboundConstants.PORT_OPEN_MAX_DELAY_IN_MINS, TimeUnit.MINUTES);
116
117         LOG.info("HwvtepSouthboundProvider Session Initiated");
118     }
119
120     @PreDestroy
121     @Deactivate
122     @Override
123     public void close() {
124         if (cm != null) {
125             cm.close();
126             cm = null;
127         }
128         if (registration != null) {
129             registration.close();
130             registration = null;
131         }
132         if (providerOwnershipChangeListener != null) {
133             providerOwnershipChangeListener.close();
134             providerOwnershipChangeListener = null;
135         }
136         if (hwvtepDTListener != null) {
137             hwvtepDTListener.close();
138             hwvtepDTListener = null;
139         }
140         if (hwvtepReconciliationManager != null) {
141             hwvtepReconciliationManager.close();
142             hwvtepReconciliationManager = null;
143         }
144         if (operTopologyRegistration != null) {
145             operTopologyRegistration.close();
146             operTopologyRegistration = null;
147         }
148         LOG.info("HwvtepSouthboundProvider Closed");
149     }
150
151     private void initializeHwvtepTopology(final LogicalDatastoreType type) {
152         InstanceIdentifier<Topology> path = InstanceIdentifier
153                 .create(NetworkTopology.class)
154                 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
155         ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
156         FluentFuture<Boolean> hwvtepTp = transaction.exists(type, path);
157         try {
158             if (!hwvtepTp.get().booleanValue()) {
159                 TopologyBuilder tpb = new TopologyBuilder();
160                 tpb.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
161                 transaction.mergeParentStructurePut(type, path, tpb.build());
162                 transaction.commit();
163             } else {
164                 transaction.cancel();
165             }
166         } catch (InterruptedException | ExecutionException e) {
167             LOG.error("Error initializing hwvtep topology", e);
168         }
169     }
170
171     public void handleOwnershipChange(final EntityOwnershipChange ownershipChange) {
172         if (ownershipChange.getState().isOwner()) {
173             LOG.info("*This* instance of HWVTEP southbound provider is set as a MASTER instance");
174             LOG.info("Initialize HWVTEP topology {} in operational and config data store if not already present",
175                     HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
176             initializeHwvtepTopology(LogicalDatastoreType.OPERATIONAL);
177             initializeHwvtepTopology(LogicalDatastoreType.CONFIGURATION);
178         } else {
179             LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
180         }
181     }
182
183
184     @Override
185     public void onDataTreeChanged(final Collection<DataTreeModification<Topology>> collection) {
186         openOvsdbPort();
187
188         if (operTopologyRegistration != null) {
189             operTopologyRegistration.close();
190             operTopologyRegistration = null;
191         }
192     }
193
194     private void openOvsdbPort() {
195         if (!registered.getAndSet(true)) {
196             LOG.info("Starting the ovsdb port");
197             ovsdbConnection.registerConnectionListener(cm);
198             ovsdbConnection.startOvsdbManager();
199         }
200     }
201
202     private static final class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
203         private final HwvtepSouthboundProvider hsp;
204         private final EntityOwnershipListenerRegistration listenerRegistration;
205
206         HwvtepsbPluginInstanceEntityOwnershipListener(final HwvtepSouthboundProvider hsp,
207                 final EntityOwnershipService entityOwnershipService) {
208             this.hsp = hsp;
209             listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
210         }
211
212         public void close() {
213             listenerRegistration.close();
214         }
215
216         @Override
217         public void ownershipChanged(final EntityOwnershipChange ownershipChange) {
218             hsp.handleOwnershipChange(ownershipChange);
219         }
220     }
221
222     @Override
223     public Map<InstanceIdentifier<Node>, HwvtepDeviceInfo> getAllConnectedInstances() {
224         return cm.allConnectedInstances();
225     }
226
227     @Override
228     public Map<InstanceIdentifier<Node>, TransactionHistory> getControllerTxHistory() {
229         return cm.controllerTxHistory();
230     }
231
232     @Override
233     public Map<InstanceIdentifier<Node>, TransactionHistory> getDeviceUpdateHistory() {
234         return cm.deviceUpdateHistory();
235     }
236 }