b1a162a3bf2abc6f5bfbb764bb65fdaaeaf2b824
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / listeners / NetworkModelListenerImpl.java
1 /*
2  * Copyright © 2020 Nokia, 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 package org.opendaylight.transportpce.servicehandler.listeners;
9
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Optional;
15 import java.util.stream.Collectors;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
18 import org.opendaylight.transportpce.common.OperationResult;
19 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
20 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult;
21 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TransportpceNetworkmodelListener;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChanges;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesKey;
24 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
27 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirection;
28 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirectionBuilder;
29 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirection;
30 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirectionBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZ;
32 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZKey;
34 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToA;
35 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToABuilder;
36 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToAKey;
37 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.Resource;
38 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.ResourceBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.resource.resource.TerminationPoint;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.path.PathDescription;
41 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.path.PathDescriptionBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
43 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class NetworkModelListenerImpl implements TransportpceNetworkmodelListener {
48
49     private static final Logger LOG = LoggerFactory.getLogger(NetworkModelListenerImpl.class);
50     private final NotificationPublishService notificationPublishService; // to be used for T-API notification
51     private ServiceDataStoreOperations serviceDataStoreOperations;
52     private TopologyUpdateResult topologyUpdateResult;
53
54     public NetworkModelListenerImpl(NotificationPublishService notificationPublishService,
55                                     ServiceDataStoreOperations serviceDataStoreOperations) {
56         this.notificationPublishService = notificationPublishService;
57         this.serviceDataStoreOperations = serviceDataStoreOperations;
58     }
59
60     @Override
61     public void onTopologyUpdateResult(TopologyUpdateResult notification) {
62         LOG.debug("Topology update notification: {}", notification.toString());
63         if (compareTopologyUpdateResult(notification)) {
64             LOG.warn("TopologyUpdateResult already wired !");
65             return;
66         }
67         topologyUpdateResult = notification;
68         // Update service datastore and service path description
69         updateServicePaths(notification);
70     }
71
72     /**
73      * Process topology update result.
74      * @param notification the result notification.
75      */
76     private void updateServicePaths(TopologyUpdateResult notification) {
77         @Nullable
78         Map<TopologyChangesKey, TopologyChanges> topologyChanges = notification.getTopologyChanges();
79         Optional<ServicePathList> servicePathListOptional = this.serviceDataStoreOperations.getServicePaths();
80         ServicePathList servicePathList = null;
81         if (!servicePathListOptional.isPresent()) {
82             LOG.warn("Enable to retrieve service path list");
83             return;
84         }
85         servicePathList = servicePathListOptional.get();
86         for (ServicePaths servicePaths : servicePathList.getServicePaths().values()) {
87             String serviceName = servicePaths.getServicePathName();
88             PathDescription pathDescription = servicePaths.getPathDescription();
89             // update path descriptions in the datastore
90             Map<AToZKey, AToZ> updatedAtoZ = changePathElementStateAZ(topologyChanges, pathDescription);
91             Map<ZToAKey, ZToA> updatedZtoA = changePathElementStateZA(topologyChanges, pathDescription);
92             OperationResult operationResult = this.serviceDataStoreOperations
93                     .modifyServicePath(buildNewPathDescription(pathDescription, updatedAtoZ, updatedZtoA), serviceName);
94             if (!operationResult.isSuccess()) {
95                 LOG.warn("Service Path not updated in datastore!");
96                 continue;
97             }
98             // update service in the datastore. Only path description with all elements in service can have a service
99             // in service. Therefore we check if all the states of the path description resources are inService
100             Optional<Services> serviceOptional = this.serviceDataStoreOperations.getService(serviceName);
101             Services services = null;
102             if (!serviceOptional.isPresent()) {
103                 LOG.error("Couldn't retrieve service");
104                 continue;
105             }
106             services = serviceOptional.get();
107             OperationResult operationResult1 = null;
108             switch (services.getOperationalState()) {
109                 case InService:
110                     if (!allElementsinPathinService(updatedAtoZ, updatedZtoA)) {
111                         LOG.debug("Service={} needs to be updated to outOfService", serviceName);
112                         //if (operationResult1 != null && operationResult1.isSuccess()) {
113                         //null check probably no more needed
114                         if (this.serviceDataStoreOperations
115                                 .modifyService(serviceName, State.OutOfService, AdminStates.OutOfService)
116                                 .isSuccess()) {
117                             LOG.info("Service state of {} correctly updated to outOfService in datastore", serviceName);
118                             continue;
119                         } else {
120                             LOG.error("Service state of {} cannot be updated to outOfService in datastore",
121                                 serviceName);
122                         }
123                     }
124                     break;
125                 case OutOfService:
126                     if (allElementsinPathinService(updatedAtoZ, updatedZtoA)) {
127                         LOG.debug("Service={} needs to be updated to inService", serviceName);
128                         //if (operationResult1 != null && operationResult1.isSuccess()) {
129                         //null check probably no more needed
130                         if (this.serviceDataStoreOperations
131                                 .modifyService(serviceName, State.InService, AdminStates.InService)
132                                 .isSuccess()) {
133                             LOG.info("Service state of {} correctly updated to inService in datastore", serviceName);
134                             continue;
135                         } else {
136                             LOG.error("Service state of {} cannot be updated to inService in datastore", serviceName);
137                         }
138                     }
139                     break;
140                 default:
141                     LOG.warn("Service {} state not managed", serviceName);
142                     continue;
143             }
144             LOG.debug("Service {} state does not need to be modified", serviceName);
145         }
146     }
147
148     private Map<ZToAKey, ZToA> changePathElementStateZA(Map<TopologyChangesKey, TopologyChanges> topologyChanges,
149         PathDescription pathDescription) {
150
151         Map<ZToAKey, ZToA> newztoaMap = new HashMap<>(pathDescription.getZToADirection().getZToA());
152         List<ZToA> tpResources = pathDescription.getZToADirection().getZToA().values().stream()
153             .filter(ele -> ele.getResource().getResource().implementedInterface().getSimpleName()
154                 .equals("TerminationPoint"))
155             .collect(Collectors.toList());
156         for (ZToA ztoA : tpResources) {
157             String ztoAid = ztoA.getId();
158             State ztoAState = ztoA.getResource().getState();
159             TerminationPoint tp = (TerminationPoint) ztoA.getResource().getResource();
160             if (topologyChanges.containsKey(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
161                 && !topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId())).getState()
162                 .equals(ztoAState)) {
163                 LOG.debug("updating ztoa tp {}", ztoA);
164                 State updatedState = topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
165                     .getState();
166                 Resource updatedResource = new ResourceBuilder()
167                     .setResource(tp)
168                     .setState(updatedState)
169                     .build();
170                 ZToA updatedZToA = new ZToABuilder(ztoA)
171                     .setId(ztoAid)
172                     .setResource(updatedResource)
173                     .build();
174                 newztoaMap.put(updatedZToA.key(), updatedZToA);
175             }
176         }
177         return newztoaMap;
178     }
179
180     private Map<AToZKey, AToZ> changePathElementStateAZ(Map<TopologyChangesKey,
181             TopologyChanges> topologyChanges, PathDescription pathDescription) {
182
183         Map<AToZKey, AToZ> newatozMap = new HashMap<>(pathDescription.getAToZDirection().getAToZ());
184         List<AToZ> tpResources = pathDescription.getAToZDirection().getAToZ().values().stream()
185             .filter(ele -> ele.getResource().getResource().implementedInterface().getSimpleName()
186                 .equals("TerminationPoint"))
187             .collect(Collectors.toList());
188         for (AToZ atoZ : tpResources) {
189             String atoZid = atoZ.getId();
190             State atoZState = atoZ.getResource().getState();
191             TerminationPoint tp = (TerminationPoint) atoZ.getResource().getResource();
192             if (topologyChanges.containsKey(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
193                 && !topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId())).getState()
194                 .equals(atoZState)) {
195                 LOG.debug("updating atoz tp {}", atoZ);
196                 State updatedState = topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
197                     .getState();
198                 Resource updatedResource = new ResourceBuilder()
199                     .setResource(tp)
200                     .setState(updatedState)
201                     .build();
202                 AToZ updatedAToZ = new AToZBuilder(atoZ)
203                     .setId(atoZid)
204                     .setResource(updatedResource)
205                     .build();
206                 newatozMap.put(updatedAToZ.key(), updatedAToZ);
207             }
208         }
209         return newatozMap;
210     }
211
212     private PathDescription buildNewPathDescription(PathDescription pathDescription, Map<AToZKey, AToZ> updatedAtoZ,
213                                                     Map<ZToAKey, ZToA> updatedZtoA) {
214         AToZDirection atozDir = new AToZDirectionBuilder(pathDescription.getAToZDirection())
215                 .setAToZ(updatedAtoZ)
216                 .build();
217         ZToADirection ztoaDir = new ZToADirectionBuilder(pathDescription.getZToADirection())
218                 .setZToA(updatedZtoA)
219                 .build();
220         return new PathDescriptionBuilder()
221             .setAToZDirection(atozDir)
222             .setZToADirection(ztoaDir)
223             .build();
224     }
225
226     private boolean allElementsinPathinService(Map<AToZKey, AToZ> updatedAtoZ, Map<ZToAKey, ZToA> updatedZtoA) {
227         boolean allEleminService = true;
228         Iterator<AToZ> i1 = updatedAtoZ.values().iterator();
229         Iterator<ZToA> i2 = updatedZtoA.values().iterator();
230         // TODO: both directions have same length?
231         while (i1.hasNext() && i2.hasNext()) {
232             if (State.OutOfService.getIntValue() == i1.next().getResource().getState().getIntValue()
233                     || State.OutOfService.getIntValue() == i2.next().getResource().getState().getIntValue()) {
234                 allEleminService = false;
235                 break;
236             }
237         }
238
239         return allEleminService;
240     }
241
242     private boolean compareTopologyUpdateResult(TopologyUpdateResult notification) {
243         if (topologyUpdateResult == null) {
244             return false;
245         }
246         if (topologyUpdateResult.getTopologyChanges().values()
247                 .equals(notification.getTopologyChanges().values())) {
248             return false;
249         }
250         return true;
251     }
252
253     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
254         this.serviceDataStoreOperations = serviceData;
255     }
256 }