apply checkstyle check during build for location-providers
[groupbasedpolicy.git] / location-providers / ne-location-provider / src / main / java / org / opendaylight / groupbasedpolicy / ne / location / provider / NeLocationProvider.java
1 /*
2  * Copyright (c) 2016 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.groupbasedpolicy.ne.location.provider;
10
11 import com.google.common.annotations.VisibleForTesting;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17
18 import javax.annotation.Nullable;
19
20 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
28 import org.opendaylight.groupbasedpolicy.util.IidFactory;
29 import org.opendaylight.groupbasedpolicy.util.NetUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElements;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElementsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElement;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.Interface;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetwork;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class NeLocationProvider implements ClusteredDataTreeChangeListener<NetworkElements>, AutoCloseable {
49
50     private static final Logger LOG = LoggerFactory.getLogger(NeLocationProvider.class);
51     public static final String NE_LOCATION_PROVIDER_NAME = "ne-location-provider";
52
53     private List<AddressEndpoint> endpoints;
54     private NetworkElements networkElements;
55     private DataBroker dataBroker;
56     private ListenerRegistration<NeLocationProvider> listenerRegistration;
57     private EndpointsListener endpointsListener;
58
59     public NeLocationProvider(DataBroker dataBroker) {
60         this.listenerRegistration =
61                 dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
62                         InstanceIdentifier.builder(NetworkElements.class).build()), this);
63         this.endpoints = new ArrayList<>();
64         this.networkElements = new NetworkElementsBuilder().build();
65         this.dataBroker = dataBroker;
66         this.endpointsListener = new EndpointsListener(dataBroker, this);
67         LOG.info("NE location provider created");
68     }
69
70     @Override
71     public void close() {
72         this.listenerRegistration.close();
73         this.endpointsListener.close();
74     }
75
76     public synchronized void onEndpointsChange(Collection<DataTreeModification<AddressEndpoint>> changes) {
77         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
78         for (DataTreeModification<AddressEndpoint> change : changes) {
79             switch (change.getRootNode().getModificationType()) {
80                 case DELETE: {
81                     AddressEndpoint endpoint = change.getRootNode().getDataBefore();
82                     removeLocationForEndpoint(endpoint, wtx);
83                     this.endpoints.remove(endpoint);
84                     break;
85                 }
86                 case WRITE: {
87                     AddressEndpoint endpoint = change.getRootNode().getDataBefore();
88                     if (endpoint != null) {
89                         this.endpoints.remove(endpoint);
90                         this.endpoints.add(change.getRootNode().getDataAfter());
91                         break;
92                     }
93                     endpoint = change.getRootNode().getDataAfter();
94                     createLocationForEndpoint(endpoint, wtx);
95                     this.endpoints.add(endpoint);
96                     break;
97                 }
98                 case SUBTREE_MODIFIED: {
99                     this.endpoints.remove(change.getRootNode().getDataBefore());
100                     this.endpoints.add(change.getRootNode().getDataAfter());
101                     break;
102                 }
103                 default:
104                     //noop
105                     break;
106             }
107         }
108         DataStoreHelper.submitToDs(wtx);
109     }
110
111     private void createLocationForEndpoint(AddressEndpoint endpoint, WriteTransaction wtx) {
112         for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
113             for (Interface iface : nullToEmpty(ne.getInterface())) {
114                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
115                     if (endpoint.getContextType().isAssignableFrom(L3Context.class)
116                             && endpoint.getContextId().equals(en.getL3ContextId())
117                             && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
118                                 .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
119                         InstanceIdentifier<AbsoluteLocation> iid = IidFactory
120                             .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
121                                     endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
122                             .child(AbsoluteLocation.class);
123                         wtx.put(LogicalDatastoreType.CONFIGURATION, iid,
124                             createRealLocation(ne.getIid(), iface.getIid()),
125                                 true);
126                         LOG.debug("New location created for endpoint {}", endpoint);
127                         return;
128                     }
129                 }
130             }
131         }
132     }
133
134     private void removeLocationForEndpoint(AddressEndpoint endpoint, WriteTransaction wtx) {
135         for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
136             for (Interface iface : nullToEmpty(ne.getInterface())) {
137                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
138                     if (endpoint.getContextType().isAssignableFrom(L3Context.class)
139                             && endpoint.getContextId().equals(en.getL3ContextId())
140                             && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
141                                 .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
142                         InstanceIdentifier<AbsoluteLocation> iid = IidFactory
143                             .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
144                                     endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
145                             .child(AbsoluteLocation.class);
146                         wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
147                         LOG.debug("Location deleted for endpoint {}", endpoint);
148                         return;
149                     }
150                 }
151             }
152         }
153     }
154
155     @Override
156     public synchronized void onDataTreeChanged(Collection<DataTreeModification<NetworkElements>> changes) {
157         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
158         for (DataTreeModification<NetworkElements> change : changes) {
159             switch (change.getRootNode().getModificationType()) {
160                 case DELETE: {
161                     NetworkElements nes = change.getRootNode().getDataBefore();
162                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
163                         for (Interface iface : nullToEmpty(ne.getInterface())) {
164                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
165                                 processDeletedEN(en, wtx);
166                             }
167                         }
168                     }
169                     networkElements = new NetworkElementsBuilder().build();
170                     LOG.debug("Network elements removed");
171                     break;
172                 }
173                 case WRITE: {
174                     NetworkElements nes = change.getRootNode().getDataBefore();
175                     if (nes != null) {
176                         for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
177                             for (Interface iface : nullToEmpty(ne.getInterface())) {
178                                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
179                                     processDeletedEN(en, wtx);
180                                 }
181                             }
182                         }
183                     }
184                     nes = change.getRootNode().getDataAfter();
185                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
186                         for (Interface iface : nullToEmpty(ne.getInterface())) {
187                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
188                                 processCreatedEN(en, ne.getIid(), iface.getIid(), wtx);
189                             }
190                         }
191                     }
192                     networkElements = nes;
193                     LOG.debug("New Network elements created {}", change.getRootNode().getDataAfter());
194                     break;
195                 }
196                 case SUBTREE_MODIFIED: {
197                     List<DataObjectModification<NetworkElement>> modifiedNetworkElements =
198                             getModifiedNetworkElements(change.getRootNode());
199                     for (DataObjectModification<NetworkElement> netElement : modifiedNetworkElements) {
200                         processNetworkElementChange(netElement, wtx);
201                     }
202                     break;
203                 }
204                 default:
205                     //noop
206                     break;
207             }
208         }
209         DataStoreHelper.submitToDs(wtx);
210     }
211
212     private List<DataObjectModification<NetworkElement>> getModifiedNetworkElements(
213             DataObjectModification<NetworkElements> modifiedNEs) {
214         Collection<DataObjectModification<? extends DataObject>> modifiedNetworkElements =
215                 modifiedNEs.getModifiedChildren();
216         List<DataObjectModification<NetworkElement>> nes = new ArrayList<>();
217         for (DataObjectModification<? extends DataObject> modifiedNetworkElement : modifiedNetworkElements) {
218             if (modifiedNetworkElement.getDataType().isAssignableFrom(NetworkElement.class)) {
219                 nes.add((DataObjectModification<NetworkElement>) modifiedNetworkElement);
220             }
221         }
222         return nes;
223     }
224
225     private void processNetworkElementChange(DataObjectModification<NetworkElement> netElement, WriteTransaction wtx) {
226         switch (netElement.getModificationType()) {
227             case DELETE: {
228                 NetworkElement ne = netElement.getDataBefore();
229                 for (Interface iface : nullToEmpty(ne.getInterface())) {
230                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
231                         processDeletedEN(en, wtx);
232                     }
233                 }
234                 networkElements.getNetworkElement().remove(ne);
235                 LOG.debug("Netowrk element {} removed", netElement.getDataBefore());
236                 break;
237             }
238             case WRITE: {
239                 NetworkElement ne = netElement.getDataBefore();
240                 if (ne != null) {
241                     for (Interface iface : nullToEmpty(ne.getInterface())) {
242                         for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
243                             processDeletedEN(en, wtx);
244                         }
245                     }
246                     networkElements.getNetworkElement().remove(ne);
247                 }
248                 ne = netElement.getDataAfter();
249                 for (Interface iface : nullToEmpty(ne.getInterface())) {
250                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
251                         processCreatedEN(en, ne.getIid(), iface.getIid(), wtx);
252                     }
253                 }
254                 networkElements.getNetworkElement().add(ne);
255                 LOG.debug("Created new Network element {}", netElement.getDataAfter());
256                 break;
257             }
258             case SUBTREE_MODIFIED: {
259                 List<DataObjectModification<Interface>> modifiedInterfaces = getModifiedInterfaces(netElement);
260                 for (DataObjectModification<Interface> modifiedInterface : modifiedInterfaces) {
261                     processInterfaceChange(modifiedInterface, netElement.getDataBefore(), wtx);
262                 }
263                 break;
264             }
265             default:
266                 //noop
267                 break;
268         }
269     }
270
271     private List<DataObjectModification<Interface>> getModifiedInterfaces(
272             DataObjectModification<NetworkElement> netElement) {
273         Collection<DataObjectModification<? extends DataObject>> potentialModifiedInterfaces =
274                 netElement.getModifiedChildren();
275         if (potentialModifiedInterfaces == null) {
276             return Collections.emptyList();
277         }
278         List<DataObjectModification<Interface>> interfaces = new ArrayList<>();
279         for (DataObjectModification<? extends DataObject> potentialModifiedInterface : potentialModifiedInterfaces) {
280             if (potentialModifiedInterface.getDataType().isAssignableFrom(Interface.class)) {
281                 interfaces.add((DataObjectModification<Interface>) potentialModifiedInterface);
282             }
283         }
284         return interfaces;
285     }
286
287     private void processInterfaceChange(DataObjectModification<Interface> modifiedInterface,
288             NetworkElement nodeBefore, WriteTransaction wtx) {
289         switch (modifiedInterface.getModificationType()) {
290             case DELETE: {
291                 Interface iface = modifiedInterface.getDataBefore();
292                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
293                     processDeletedEN(en, wtx);
294                 }
295                 int nodeIndex = getIndexOf(nodeBefore);
296                 networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
297                 LOG.debug("Interface {} removed", modifiedInterface.getDataBefore());
298                 break;
299             }
300             case WRITE: {
301                 Interface iface = modifiedInterface.getDataBefore();
302                 int nodeIndex = getIndexOf(nodeBefore);
303                 if (iface != null) {
304                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
305                         processDeletedEN(en, wtx);
306                     }
307                     networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
308                 }
309                 iface = modifiedInterface.getDataAfter();
310                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
311                     processCreatedEN(en, nodeBefore.getIid(), iface.getIid(), wtx);
312                 }
313                 networkElements.getNetworkElement().get(nodeIndex).getInterface().add(iface);
314                 LOG.debug("Created new Interface {}", modifiedInterface.getDataAfter());
315                 break;
316             }
317             case SUBTREE_MODIFIED: {
318                 List<DataObjectModification<EndpointNetwork>> modifiedENs =
319                         getModifiedEndpointNetworks(modifiedInterface);
320                 for (DataObjectModification<EndpointNetwork> modifiedEN : modifiedENs) {
321                     processEndpointNetworkChange(modifiedEN, nodeBefore, modifiedInterface.getDataBefore(), wtx);
322                 }
323                 break;
324             }
325             default:
326                 //noop
327                 break;
328         }
329     }
330
331     private List<DataObjectModification<EndpointNetwork>> getModifiedEndpointNetworks(
332             DataObjectModification<Interface> modifiedInterface) {
333         Collection<DataObjectModification<? extends DataObject>> potentialModifiedEPs =
334                 modifiedInterface.getModifiedChildren();
335         if (potentialModifiedEPs == null) {
336             return Collections.emptyList();
337         }
338         List<DataObjectModification<EndpointNetwork>> eps = new ArrayList<>();
339         for (DataObjectModification<? extends DataObject> potentialModifiedEP : potentialModifiedEPs) {
340             if (potentialModifiedEP.getDataType().isAssignableFrom(EndpointNetwork.class)) {
341                 eps.add((DataObjectModification<EndpointNetwork>) potentialModifiedEP);
342             }
343         }
344         return eps;
345     }
346
347     private void processEndpointNetworkChange(DataObjectModification<EndpointNetwork> modifiedEN,
348             NetworkElement nodeBefore, Interface ifaceBefore, WriteTransaction wtx) {
349         switch (modifiedEN.getModificationType()) {
350             case DELETE: {
351                 processDeletedEN(modifiedEN.getDataBefore(), wtx);
352                 int nodeIndex = getIndexOf(nodeBefore);
353                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
354                 networkElements.getNetworkElement()
355                     .get(nodeIndex)
356                     .getInterface()
357                     .get(ifaceIndex)
358                     .getEndpointNetwork()
359                     .remove(modifiedEN.getDataBefore());
360                 LOG.debug("Endpoint network {} removed", modifiedEN.getDataBefore());
361                 break;
362             }
363             case WRITE: {
364                 processCreatedEN(modifiedEN.getDataAfter(), nodeBefore.getIid(), ifaceBefore.getIid(), wtx);
365                 int nodeIndex = getIndexOf(nodeBefore);
366                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
367                 networkElements.getNetworkElement()
368                     .get(nodeIndex)
369                     .getInterface()
370                     .get(ifaceIndex)
371                     .getEndpointNetwork()
372                     .add(modifiedEN.getDataAfter());
373                 LOG.debug("Created new Endpoint network {}", modifiedEN.getDataAfter());
374                 break;
375             }
376             case SUBTREE_MODIFIED: {
377                 LOG.debug("EndpointNetwork {} changed", modifiedEN.getDataAfter().getKey());
378                 break;
379             }
380             default:
381                 //noop
382                 break;
383         }
384     }
385
386     private void processCreatedEN(EndpointNetwork en, InstanceIdentifier<?> nodeIID,
387             String connectorIID, WriteTransaction wtx) {
388         for (AddressEndpoint endpoint : endpoints) {
389             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
390                     && endpoint.getContextId().equals(en.getL3ContextId())
391                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
392                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
393                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
394                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
395                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
396                     .child(AbsoluteLocation.class);
397                 wtx.put(LogicalDatastoreType.CONFIGURATION, iid, createRealLocation(nodeIID, connectorIID), true);
398                 LOG.debug("New location created for endpoint {}", endpoint);
399             }
400         }
401         return;
402     }
403
404     private void processDeletedEN(EndpointNetwork en, WriteTransaction wtx) {
405         for (AddressEndpoint endpoint : endpoints) {
406             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
407                     && endpoint.getContextId().equals(en.getL3ContextId())
408                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
409                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
410                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
411                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
412                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
413                     .child(AbsoluteLocation.class);
414                 wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
415                 LOG.debug("Location deleted for endpoint {}", endpoint);
416             }
417         }
418         return;
419     }
420
421     private AbsoluteLocation createRealLocation(InstanceIdentifier<?> node, String iface) {
422         return new AbsoluteLocationBuilder()
423             .setLocationType(new ExternalLocationCaseBuilder().setExternalNodeMountPoint(node)
424                     .setExternalNodeConnector(iface).build()).build();
425     }
426
427     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
428         return list == null ? Collections.emptyList() : list;
429     }
430
431     private int getIndexOf(NetworkElement ne) {
432         for (NetworkElement listNE : networkElements.getNetworkElement()) {
433             if (ne.getIid().equals(listNE.getIid())) {
434                 return networkElements.getNetworkElement().indexOf(listNE);
435             }
436         }
437         return -1;
438     }
439
440     private int getIndexOf(Interface iface, int nodeIndex) {
441         for (Interface listIface : networkElements.getNetworkElement().get(nodeIndex).getInterface()) {
442             if (iface.getIid().equals(listIface.getIid())) {
443                 return networkElements.getNetworkElement().get(nodeIndex).getInterface().indexOf(listIface);
444             }
445         }
446         return -1;
447     }
448
449     @VisibleForTesting
450     synchronized List<AddressEndpoint> getEndpoints() {
451         return endpoints;
452     }
453
454     @VisibleForTesting
455     synchronized NetworkElements getNetworkElements() {
456         return networkElements;
457     }
458 }