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