Merge "Fixed main issues of SwitchManager"
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / node / FlowCapableNodeConnectorListener.java
1 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.Map;
8 import java.util.Map.Entry;
9
10 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
11 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
12 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
13 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
14 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
16 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
31 import org.opendaylight.yangtools.concepts.ListenerRegistration;
32 import org.opendaylight.yangtools.yang.binding.DataObject;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.common.base.Objects;
38 import com.google.common.base.Optional;
39 import com.google.common.util.concurrent.Futures;
40
41 public class FlowCapableNodeConnectorListener implements DataChangeListener, AutoCloseable {
42
43     private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeConnectorListener.class);
44
45     private final static InstanceIdentifier<FlowCapableNodeConnector> fcNodeConnectorIid = InstanceIdentifier.builder(
46             Nodes.class)
47         .child(Node.class)
48         .child(NodeConnector.class)
49         .augmentation(FlowCapableNodeConnector.class)
50         .build();
51     private final static InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
52         .build();
53     private final DataBroker dataProvider;
54     private final SwitchManager switchManager;
55     private final ListenerRegistration<DataChangeListener> listenerRegistration;
56
57     public FlowCapableNodeConnectorListener(DataBroker dataProvider, SwitchManager switchManager) {
58         this.dataProvider = checkNotNull(dataProvider);
59         this.switchManager = checkNotNull(switchManager);
60         listenerRegistration = dataProvider.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
61                 fcNodeConnectorIid, this, DataChangeScope.BASE);
62     }
63
64     @Override
65     public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
66         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
67         Map<Name, Endpoint> epWithOfOverlayAugByPortName = readEpsWithOfOverlayAugByPortName(rwTx);
68         boolean isDataPutToTx = false;
69         for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getCreatedData().entrySet()) {
70             if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) {
71                 InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class);
72                 FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue();
73                 LOG.trace(
74                         "FlowCapableNodeConnector created: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}",
75                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
76                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc);
77                 switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc);
78                 Name portName = getPortName(fcnc);
79                 boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
80                 if (updated == true) {
81                     isDataPutToTx = true;
82                 }
83             }
84         }
85         for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getUpdatedData().entrySet()) {
86             if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) {
87                 InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class);
88                 FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue();
89                 LOG.trace(
90                         "FlowCapableNodeConnector updated: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}",
91                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
92                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc);
93                 switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc);
94                 Name portName = getPortName(fcnc);
95                 boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
96                 if (updated == true) {
97                     isDataPutToTx = true;
98                 }
99                 FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData().get(
100                         fcncEntry.getKey());
101                 Name portNameFromOriginalFcnc = getPortName(originalFcnc);
102                 // portname already existed and then was changed
103                 if (portNameFromOriginalFcnc != null && !Objects.equal(portNameFromOriginalFcnc, portName)) {
104                     updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc),
105                             null, rwTx);
106                     if (updated == true) {
107                         isDataPutToTx = true;
108                     }
109                 }
110             }
111         }
112         for (InstanceIdentifier<?> fcncIid : change.getRemovedPaths()) {
113             if (FlowCapableNodeConnector.class.equals(fcncIid.getTargetType())) {
114                 InstanceIdentifier<NodeConnector> ncIid = fcncIid.firstIdentifierOf(NodeConnector.class);
115                 FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData()
116                     .get(fcncIid);
117                 LOG.trace("FlowCapableNodeConnector removed: NodeId: {} NodeConnectorId: {}",
118                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
119                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue());
120                 switchManager.updateSwitchNodeConnectorConfig(ncIid, null);
121                 Name portNameFromOriginalFcnc = getPortName(originalFcnc);
122                 boolean updated = updateEpWithNodeConnectorInfo(
123                         epWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc), null, rwTx);
124                 if (updated == true) {
125                     isDataPutToTx = true;
126                 }
127             }
128         }
129         if (isDataPutToTx) {
130             rwTx.submit();
131         } else {
132             rwTx.cancel();
133         }
134     }
135
136     private Map<Name, Endpoint> readEpsWithOfOverlayAugByPortName(ReadTransaction rTx) {
137         Optional<Endpoints> potentialEps = Futures.getUnchecked(rTx.read(LogicalDatastoreType.OPERATIONAL, endpointsIid));
138         if (!potentialEps.isPresent() || potentialEps.get().getEndpoint() == null) {
139             return Collections.emptyMap();
140         }
141         Map<Name, Endpoint> epsByPortName = new HashMap<>();
142         for (Endpoint ep : potentialEps.get().getEndpoint()) {
143             OfOverlayContext ofOverlayEp = ep.getAugmentation(OfOverlayContext.class);
144             if (ofOverlayEp != null && ofOverlayEp.getPortName() != null) {
145                 epsByPortName.put(ofOverlayEp.getPortName(), ep);
146             }
147         }
148         return epsByPortName;
149     }
150
151     private Name getPortName(FlowCapableNodeConnector fcnc) {
152         if (fcnc == null || fcnc.getName() == null) {
153             return null;
154         }
155         return new Name(fcnc.getName());
156     }
157
158     /**
159      * @return {@code true} if data was put to the transaction; {@code false} otherwise
160      */
161     private boolean updateEpWithNodeConnectorInfo(Endpoint epWithOfOverlayAug, InstanceIdentifier<NodeConnector> ncIid,
162             WriteTransaction tx) {
163         if (epWithOfOverlayAug == null) {
164             return false;
165         }
166         OfOverlayContext oldOfOverlayAug = epWithOfOverlayAug.getAugmentation(OfOverlayContext.class);
167         OfOverlayContextBuilder newOfOverlayAug = new OfOverlayContextBuilder(oldOfOverlayAug);
168         if (ncIid == null && oldOfOverlayAug.getNodeConnectorId() == null) {
169             return false;
170         }
171         if (ncIid != null) {
172             NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
173             if (ncId.equals(oldOfOverlayAug.getNodeConnectorId())) {
174                 return false;
175             }
176             NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
177             newOfOverlayAug.setNodeId(nodeId);
178             newOfOverlayAug.setNodeConnectorId(ncId);
179         }
180         InstanceIdentifier<OfOverlayContext> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class)
181             .child(Endpoint.class, epWithOfOverlayAug.getKey())
182             .augmentation(OfOverlayContext.class)
183             .build();
184         tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayAug.build());
185         return true;
186     }
187
188     @Override
189     public void close() throws Exception {
190         if (listenerRegistration != null) {
191             listenerRegistration.close();
192         }
193     }
194
195 }