fix ServiceHandler SpotBugs false positives
[transportpce.git] / tests / honeynode / 2.2.1 / honeynode-plugin-impl / src / main / java / io / fd / honeycomb / transportpce / device / write / DeviceChangeListener.java
1 /*
2  * Copyright (c) 2018 Orange and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.fd.honeycomb.transportpce.device.write;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.concurrent.ExecutionException;
23
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.DataObjectModification;
27 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
28 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
29 import org.opendaylight.mdsal.binding.api.DataTreeModification;
30 import org.opendaylight.mdsal.binding.api.ReadTransaction;
31 import org.opendaylight.mdsal.binding.api.WriteTransaction;
32 import org.opendaylight.mdsal.common.api.CommitInfo;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.pack.Ports;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.pack.PortsBuilder;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.packs.CircuitPacks;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.packs.CircuitPacksKey;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.interfaces.grp.Interface;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.interfaces.grp.InterfaceKey;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDeviceBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.OduConnection;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.OduConnectionKey;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.RoadmConnections;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsKey;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.InterfacesBuilder;
48 import org.opendaylight.yangtools.yang.binding.DataObject;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Preconditions;
55 import com.google.common.util.concurrent.FluentFuture;
56
57 /**
58  * @author Martial COULIBALY ( mcoulibaly.ext@orange.com ) on behalf of Orange
59  */
60 final class DeviceChangeListener implements DataTreeChangeListener<OrgOpenroadmDevice> {
61
62     private static final Logger LOG = LoggerFactory.getLogger(DeviceChangeListener.class);
63     private final DataBroker dataBroker;
64
65     public DeviceChangeListener(DataBroker deviceDataBroker) {
66         this.dataBroker = deviceDataBroker;
67         Preconditions.checkArgument(this.dataBroker != null, "Device datastore is null");
68     }
69
70     @Override
71     public void onDataTreeChanged(Collection<DataTreeModification<OrgOpenroadmDevice>> changes) {
72         LOG.info("onDataTreeChanged");
73         for (DataTreeModification<OrgOpenroadmDevice> change : changes) {
74             final DataObjectModification<OrgOpenroadmDevice> rootNode = change.getRootNode();
75             final DataTreeIdentifier<OrgOpenroadmDevice> rootPath = change.getRootPath();
76             if (rootNode != null ) {
77                 final OrgOpenroadmDevice dataBefore = rootNode.getDataBefore();
78                 final OrgOpenroadmDevice dataAfter = rootNode.getDataAfter();
79                 LOG.info("Received Device change({}):\n before={} \n after={}", rootNode.getModificationType(), dataBefore,
80                         dataAfter);
81                 Collection<? extends DataObjectModification<? extends DataObject>> modifiedChildren = rootNode.getModifiedChildren();
82                 switch (rootNode.getModificationType()) {
83                     case SUBTREE_MODIFIED:
84                         if (!modifiedChildren.isEmpty()) {
85                             Iterator<? extends DataObjectModification<? extends DataObject>> iterator = modifiedChildren.iterator();
86                             while (iterator.hasNext()) {
87                                 DataObjectModification<? extends DataObject> modified = iterator.next();
88                                 LOG.info("modified = \ndataType : {}\nid : {}\nmodifiedType : {}\noldData : {}\nnewData : {} \n",
89                                         modified.getDataType(), modified.getIdentifier(),modified.getModificationType(),
90                                         modified.getDataBefore(), modified.getDataAfter());
91                                 switch (modified.getModificationType()) {
92                                   case SUBTREE_MODIFIED:
93                                   case WRITE :
94                                       processChange(rootPath.getRootIdentifier(), modified, dataAfter);
95                                       updateCircuitPackInterface(rootPath.getRootIdentifier(), modified, false);
96                                       break;
97                                   case DELETE:
98                                       updateCircuitPackInterface(rootPath.getRootIdentifier(), modified, true);
99                                       deleteContainer(rootPath, modified);
100                                       break;
101                                   default:
102                                       break;
103                                }
104                             }
105                         }
106                         //processChange(rootPath.getRootIdentifier(), dataAfter);
107                         break;
108                     case WRITE :
109                         processChange(rootPath.getRootIdentifier(), null, dataAfter);
110                         break;
111                     case DELETE:
112                         LOG.info("device config datastore is deleted !");
113                         break;
114                     default:
115                         break;
116                 }
117             } else {
118                 LOG.error("rootNode is null !");
119             }
120         }
121     }
122
123     /**
124      * Delete change from device
125      * oper datastore.
126      *
127      * @param id container identifier
128      */
129     private void deleteContainer(DataTreeIdentifier<OrgOpenroadmDevice> rootPath,
130             DataObjectModification<? extends DataObject> modified) {
131         final String ROADM_CONNECTIONS = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
132                 + ".org.openroadm.device.container.org.openroadm.device.RoadmConnections";
133         final String INTERFACE_GRP = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
134                 + ".interfaces.grp.Interface";
135         final String ODU_CONNECTIONS = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
136                 + ".org.openroadm.device.container.org.openroadm.device.OduConnection";
137         Class<? extends DataObject> type = modified.getDataType();
138         PathArgument path = modified.getIdentifier();
139         LOG.info("deleting container type '{}' with id '{}' ...", type.toString(), path);
140         String key = extractKey(path.toString());
141         if ( key != null) {
142             InstanceIdentifier<?> iid = null;
143             switch (type.toString()) {
144                 case ROADM_CONNECTIONS:
145                     LOG.info("roadm-connections ...");
146                     iid = rootPath.getRootIdentifier().child(RoadmConnections.class,
147                         new RoadmConnectionsKey(key));
148                     break;
149                 case INTERFACE_GRP:
150                     LOG.info("interface ....");
151                     iid = rootPath.getRootIdentifier().child(Interface.class,
152                             new InterfaceKey(key));
153                     break;
154                 case ODU_CONNECTIONS:
155                     LOG.info("Deleting odu connections");
156                     iid = rootPath.getRootIdentifier().child(OduConnection.class,
157                             new OduConnectionKey(key));
158                     break;
159                 default:
160                     break;
161             }
162             LOG.info("iid : {}", iid);
163             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
164             if (writeTx != null) {
165                 LOG.info("WriteTransaction is ok, delete container device from device oper datastore");
166                 try {
167                     LOG.info("deleting container element from device oper DS ...");
168                     writeTx.delete(LogicalDatastoreType.OPERATIONAL, iid);
169                     FluentFuture< ? extends @NonNull CommitInfo> future = writeTx.commit();
170                     future.get();
171                     LOG.info("container element '{}' deleted from device oper datastore", iid);
172                 } catch (InterruptedException | ExecutionException e) {
173                     LOG.error("Failed to process WriteTransactions",e);
174                 }
175             } else {
176                 LOG.error("WriteTransaction object is null");
177             }
178         } else {
179             LOG.error("extract key is null");
180         }
181     }
182
183
184
185     private String extractKey(String path) {
186         LOG.info("getting key from pathArgument ...");
187         String result = null;
188         if (path != null && path.length() > 2) {
189             result = path.substring(path.lastIndexOf("=") + 1, path.length()-2);
190             LOG.info("result : {}", result);
191         } else {
192             LOG.error("String pathArgument is not compliant !!");
193         }
194         return result;
195     }
196
197
198     /**
199      * Merge change to Honeycomb
200      * config datastore and device
201      * config datastore.
202      *
203      * @param id OrgOpenroadmDevice identifier
204      * @param dataAfter OrgOpenroadmDevice to be merged
205      */
206     private void processChange(final InstanceIdentifier<OrgOpenroadmDevice> id,
207             DataObjectModification<? extends DataObject> modified, final OrgOpenroadmDevice dataAfter) {
208         LOG.info("processing change ...");
209         WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
210         if (writeTx != null) {
211             LOG.info("WriteTransactions are ok, merge device info to datastores");
212             if(dataAfter != null) {
213                 String deviceId = dataAfter.getInfo().getNodeId().getValue();
214                 writeTx.merge(LogicalDatastoreType.OPERATIONAL, id, dataAfter);
215                 FluentFuture< ? extends @NonNull CommitInfo> future = writeTx.commit();
216                 try {
217                     future.get();
218                     LOG.info("device '{}' merged to device oper datastore", deviceId);
219                 } catch (InterruptedException | ExecutionException e) {
220                     LOG.error("Failed to merge Element '{}' to datastores", deviceId);
221                 }
222             } else {
223                 LOG.error("device is null");
224             }
225         } else {
226             LOG.error("WriteTransaction object is null");
227         }
228     }
229
230     /**
231      *Update Interface info on
232      *Ports list in CircuitPacks.
233      *
234      * @param id device InstanceIdentifier
235      * @param modified DataObjectModification
236      * @param deviceData OrgOpenroadmDevice
237      * @param delete if yes delete interface from circuitpacks else adding interface
238      */
239     private void updateCircuitPackInterface(final InstanceIdentifier<OrgOpenroadmDevice> id,
240             DataObjectModification<? extends DataObject> modified, boolean delete) {
241         LOG.info("Updating circuit packs interface ...");
242         final String INTERFACE_GRP = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
243                 + ".interfaces.grp.Interface";
244         InstanceIdentifier<CircuitPacks> iid = null;
245         if (modified != null) {
246             Class<? extends DataObject> type = modified.getDataType();
247             LOG.info("getting container type '{}' ...", type.toString());
248             if (type != null) {
249                 if (type.toString().compareTo(INTERFACE_GRP) == 0) {
250                     LOG.warn("interface update ! ");
251                     Interface data = null;
252                     if (delete) {
253                         data = (Interface) modified.getDataBefore();
254                     } else {
255                         data = (Interface) modified.getDataAfter();
256                     }
257                     LOG.info("Interface data gets : {}", data.toString());
258                     if (data!= null) {
259                         String circuitPackName = data.getSupportingCircuitPackName();
260                         String port = data.getSupportingPort().toString();
261                         String interfaceName = data.getName();
262                         if (circuitPackName != null && port != null && interfaceName != null) {
263                             iid = id.child(CircuitPacks.class,
264                                     new CircuitPacksKey(circuitPackName));
265                             OrgOpenroadmDevice operDevice = readDeviceOperData(id);
266                             if (operDevice != null) {
267                                 OrgOpenroadmDeviceBuilder builder = new OrgOpenroadmDeviceBuilder(operDevice);
268                                 List<CircuitPacks> list = builder.getCircuitPacks();
269                                 LOG.info("Getting circuit packs ...");
270                                 for (CircuitPacks circuitPacks : list) {
271                                     if (circuitPacks.getCircuitPackName().compareTo(circuitPackName) == 0) {
272                                         LOG.info("circuitpack found");
273                                         List<Ports> portList = circuitPacks.getPorts();
274                                         LOG.info("Getting ports for circuit pack '{}' ...", circuitPackName);
275                                         for (Ports ports : portList) {
276                                             if (ports.getPortName().compareTo(port) == 0) {
277                                                 LOG.info("port found");
278                                                 PortsBuilder newPorts = new PortsBuilder(ports);
279                                                 List<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
280                                                 .port.Interfaces> value = newPorts.getInterfaces();
281                                                 if (!delete) {
282                                                     LOG.info("adding interface info to port '{}'", port);
283                                                     if (value == null || value.isEmpty()) {
284                                                         LOG.info("Interfaces List is empty !");
285                                                         value = new ArrayList<org.opendaylight.yang.gen.v1.http.org
286                                                                 .openroadm.device.rev181019.port.Interfaces>();
287                                                         value.add(new InterfacesBuilder().setInterfaceName(interfaceName)
288                                                                 .build());
289                                                     } else { // value is not empty
290                                                         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
291                                                         .port.Interfaces tmp = getInterfaces(value, interfaceName);
292                                                         if( tmp != null) {
293                                                             LOG.warn("Interfaces with name '{}' already exists !",interfaceName);
294                                                             break;
295                                                         } else { // no interface found
296                                                             value.add(new InterfacesBuilder().setInterfaceName(interfaceName)
297                                                                     .build());
298                                                         }
299                                                     }
300                                                 } else {
301                                                     LOG.info("removing interface info from port '{}'", port);
302                                                     org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
303                                                     .port.Interfaces tmp = getInterfaces(value, interfaceName);
304                                                     if( tmp != null) {
305                                                         LOG.info("Interfaces with name '{}' gets",interfaceName);
306                                                         value.remove(tmp);
307                                                     }else {
308                                                         LOG.error("Interfaces list is null");
309                                                         value = new ArrayList<org.opendaylight.yang.gen.v1.http.org.openroadm
310                                                                 .device.rev181019.port.Interfaces>();
311                                                     }
312                                                 }
313                                                 newPorts.setInterfaces(value);
314                                                 portList.remove(ports);
315                                                 portList.add(newPorts.build());
316                                                 LOG.info("port list updated !");
317                                                 update(circuitPacks, iid);
318                                                 break;
319                                             }
320                                         }
321                                         break;
322                                     }
323                                 }
324                             } else {
325                                 LOG.error("reading operational device data failed !");
326                             }
327
328                         } else {
329                             LOG.error("SupportingCircuitPackName / SupportingPort / Interface Name are/is null !");
330                         }
331                     }
332                 } else {
333                     LOG.warn("not an interface update ! ");
334                 }
335             }
336         } else {
337             LOG.error("DataObjectModification is null");
338         }
339     }
340
341     /**
342      * Search in {@link Interfaces} list
343      * if an interfaces already exists.
344      *
345      * @param value Interfaces List
346      * @param interfaceName Interface Name
347      * @return Interfaces
348      */
349     private org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces getInterfaces(
350             List<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces> value,
351             String interfaceName) {
352         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces result = null;
353         if (value != null && !value.isEmpty()) {
354             LOG.info("Getting interfaces list ...");
355             for (org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
356                     .port.Interfaces tmp : value) {
357                 if( tmp != null
358                         && tmp.getInterfaceName().compareTo(interfaceName) == 0) {
359                     LOG.info("Interfaces with name '{}' gets",interfaceName);
360                     result = tmp;
361                     break;
362                 }
363             }
364         } else {
365             LOG.error("Interfaces list is empty");
366         }
367         return result;
368     }
369
370     /**
371      * Update circuitPacks information
372      * in device oper datastore.
373      *
374      * @param circuitPacks CircuitPacks data
375      * @param iid CircuitPacks InstanceIdentifier
376      * @param id OrgOpenroadmDevice InstanceIdentifier
377      * @param deviceData OrgOpenroadmDevice data
378      */
379     private void update(CircuitPacks circuitPacks, final InstanceIdentifier<CircuitPacks> iid) {
380         LOG.info("updating oper Datastore with iid : {}", iid);
381         WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
382         if (writeTx != null) {
383             LOG.info("WriteTransaction is ok, update container circuitpacks from device oper datastore");
384             try {
385                 LOG.info("updating container circuitpacks from device oper DS ...");
386                 writeTx.merge(LogicalDatastoreType.OPERATIONAL, iid,circuitPacks);
387                 FluentFuture< ? extends @NonNull CommitInfo> future = writeTx.commit();
388                 future.get();
389                 LOG.info("container circuitpacks '{}' merged to device oper datastore", iid);
390             } catch (InterruptedException | ExecutionException e) {
391                 LOG.error("Failed to process WriteTransactions",e);
392             }
393         } else {
394             LOG.error("WriteTransaction object is null");
395         }
396     }
397
398     /**
399      * Get {@link OrgOpenroadmDevice} data
400      * from operational datastore
401      *
402      * @param id OrgOpenroadmDevice InstanceIdentifier
403      * @return OrgOpenroadmDevice result
404      */
405     private OrgOpenroadmDevice readDeviceOperData(final InstanceIdentifier<OrgOpenroadmDevice> id) {
406         OrgOpenroadmDevice result = null;
407         LOG.info("reading device operational datastore ...");
408         ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction();
409         if (readTx != null) {
410             LOG.info("ReadTransaction is ok");
411             try {
412                 LOG.info("reading device from device oper DS ...");
413                 java.util.Optional<OrgOpenroadmDevice> device = readTx.read(LogicalDatastoreType.OPERATIONAL, id).get();
414                 if (device.isPresent()) {
415                     result = device.get();
416                     LOG.info("device gets from device oper datastore");
417                 }
418             } catch (InterruptedException | ExecutionException e) {
419                 LOG.error("Failed to process ReadTransaction",e);
420             }
421         } else {
422             LOG.error("ReadTransaction object is null");
423         }
424         return result;
425
426     }
427
428 }