Step 2: Migrate termination point stuff under the same transact as bridge stuff.
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / OvsdbDataChangeListener.java
1 package org.opendaylight.ovsdb.southbound;
2
3 import java.net.UnknownHostException;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Map.Entry;
7 import java.util.Set;
8
9 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
10 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
11 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
12 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.ovsdb.lib.OvsdbClient;
15 import org.opendaylight.ovsdb.southbound.ovsdb.transact.DataChangesManagedByOvsdbNodeEvent;
16 import org.opendaylight.ovsdb.southbound.ovsdb.transact.TransactCommandAggregator;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
20 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
21 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
22 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
23 import org.opendaylight.yangtools.concepts.ListenerRegistration;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import com.google.common.base.Preconditions;
30 import com.google.common.base.Predicates;
31 import com.google.common.collect.Maps;
32
33 public class OvsdbDataChangeListener implements DataChangeListener, AutoCloseable {
34
35     private ListenerRegistration<DataChangeListener> registration;
36     private OvsdbConnectionManager cm;
37     private DataBroker db;
38     private static final Logger LOG = LoggerFactory.getLogger(OvsdbDataChangeListener.class);
39
40     OvsdbDataChangeListener(DataBroker db, OvsdbConnectionManager cm) {
41         LOG.info("Registering OvsdbNodeDataChangeListener");
42         this.cm = cm;
43         this.db = db;
44         InstanceIdentifier<Node> path = InstanceIdentifier
45                 .create(NetworkTopology.class)
46                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
47                 .child(Node.class);
48         registration =
49                 db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.SUBTREE);
50
51     }
52
53     @Override
54     public void close() throws Exception {
55         registration.close();
56     }
57
58     @Override
59     public void onDataChanged(
60             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
61         // Connect first if we have to:
62         connect(changes);
63
64         // Second update connections if we have to
65         updateConnections(changes);
66
67         // Then handle updates to the actual data
68         updateData(changes);
69
70         // Finally disconnect if we need to
71         disconnect(changes);
72
73     }
74
75     private void updateData(
76             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
77         for (OvsdbConnectionInstance connectionInstance : connectionInstancesFromChanges(changes)) {
78             connectionInstance.transact(new TransactCommandAggregator(
79                     db,
80                     new DataChangesManagedByOvsdbNodeEvent(
81                             SouthboundMapper.createInstanceIdentifier(connectionInstance.getKey()),
82                             changes)));
83         }
84     }
85
86     private void disconnect(
87             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
88         Map<InstanceIdentifier<?>, DataObject> originalDataObject = changes.getOriginalData();
89         Set<InstanceIdentifier<?>> iiD = changes.getRemovedPaths();
90         for (InstanceIdentifier instanceIdentifier : iiD) {
91             if (originalDataObject.get(instanceIdentifier) instanceof OvsdbNodeAugmentation) {
92                 try {
93                     cm.disconnect((OvsdbNodeAugmentation) originalDataObject.get(instanceIdentifier));
94                 } catch (UnknownHostException e) {
95                     LOG.warn("Failed to disconnect ovsdbNode", e);
96                 }
97             }
98         }
99     }
100
101     private void updateConnections(
102             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
103         for (Entry<InstanceIdentifier<?>, DataObject> updated : changes.getUpdatedData().entrySet()) {
104             if (updated.getValue() instanceof OvsdbNodeAugmentation) {
105                 OvsdbNodeAugmentation value = (OvsdbNodeAugmentation) updated.getValue();
106                 OvsdbClient client = cm.getClient(value);
107                 if (client == null) {
108                     for (Entry<InstanceIdentifier<?>, DataObject> original : changes.getOriginalData().entrySet()) {
109                         if (original.getValue() instanceof OvsdbNodeAugmentation) {
110                             try {
111                                 cm.disconnect((OvsdbNodeAugmentation) original.getValue());
112                                 cm.connect(value);
113                             } catch (UnknownHostException e) {
114                                 LOG.warn("Failed to disconnect to ovsdbNode", e);
115                             }
116                         }
117                     }
118                 }
119             }
120         }
121     }
122
123     private void connect(
124             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
125         for (Entry<InstanceIdentifier<?>, DataObject> created : changes.getCreatedData().entrySet()) {
126             // TODO validate we have the correct kind of InstanceIdentifier
127             if (created.getValue() instanceof OvsdbNodeAugmentation) {
128                 try {
129                     cm.connect((OvsdbNodeAugmentation) created.getValue());
130                 } catch (UnknownHostException e) {
131                     LOG.warn("Failed to connect to ovsdbNode", e);
132                 }
133             }
134         }
135     }
136
137     public Set<OvsdbConnectionInstance> connectionInstancesFromChanges(
138             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
139         Set<OvsdbConnectionInstance> result = new HashSet<OvsdbConnectionInstance>();
140         result.addAll(connectionInstancesFromMap(changes.getCreatedData()));
141         result.addAll(connectionInstancesFromMap(changes.getUpdatedData()));
142         result.addAll(connectionInstancesFromMap(
143                 Maps.filterKeys(changes.getOriginalData(), Predicates.in(changes.getRemovedPaths()))));
144         return result;
145     }
146
147     public Set<OvsdbConnectionInstance> connectionInstancesFromMap(Map<InstanceIdentifier<?>, DataObject> map) {
148         Preconditions.checkNotNull(map);
149         Set<OvsdbConnectionInstance> result = new HashSet<OvsdbConnectionInstance>();
150         for ( Entry<InstanceIdentifier<?>, DataObject> created : map.entrySet()) {
151             if (created.getValue() instanceof Node) {
152                 LOG.debug("Received request to create {}",created.getValue());
153                 OvsdbBridgeAugmentation bridge =
154                         ((Node)created.getValue()).getAugmentation(OvsdbBridgeAugmentation.class);
155                 if (bridge != null) {
156                     OvsdbConnectionInstance client = cm.getConnectionInstance(bridge);
157                     if (client != null) {
158                         LOG.debug("Found client for {}", created.getValue());
159                         result.add(client);
160                     } else {
161                         LOG.debug("Did not find client for {}",created.getValue());
162                     }
163                 }
164             }
165         }
166         return result;
167     }
168
169 }