Migrate servicehandler module to OSGI DS
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / listeners / RendererListenerImpl.java
1 /*
2  * Copyright © 2017 Orange, 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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Map;
14 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
15 import org.opendaylight.transportpce.common.OperationResult;
16 import org.opendaylight.transportpce.common.StringConstants;
17 import org.opendaylight.transportpce.networkmodel.service.NetworkModelService;
18 import org.opendaylight.transportpce.pce.service.PathComputationService;
19 import org.opendaylight.transportpce.servicehandler.ServiceInput;
20 import org.opendaylight.transportpce.servicehandler.service.PCEServiceWrapper;
21 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.TransportpceRendererListener;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
26 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultSh;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultShBuilder;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.ServiceNotificationTypes;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
32 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.PublishNotificationProcessService;
33 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.PublishNotificationProcessServiceBuilder;
34 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.notification.process.service.ServiceAEndBuilder;
35 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.notification.process.service.ServiceZEndBuilder;
36 import org.osgi.service.component.annotations.Activate;
37 import org.osgi.service.component.annotations.Component;
38 import org.osgi.service.component.annotations.Reference;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * Calls to listen to Renderer notifications.
44  *
45  * @author Martial Coulibaly ( martial.coulibaly@gfi.com ) on behalf of Orange
46  *
47  */
48 @Component
49 public class RendererListenerImpl implements TransportpceRendererListener, RendererListener {
50
51     private static final String PUBLISHER = "RendererListener";
52     private static final Logger LOG = LoggerFactory.getLogger(RendererListenerImpl.class);
53     private RendererRpcResultSp serviceRpcResultSp;
54     private ServiceDataStoreOperations serviceDataStoreOperations;
55     private ServiceInput input;
56     private PCEServiceWrapper pceServiceWrapper;
57     private Boolean tempService;
58     private NotificationPublishService notificationPublishService;
59     private final NetworkModelService networkModelService;
60
61
62     @Activate
63     public RendererListenerImpl(@Reference PathComputationService pathComputationService,
64             @Reference NotificationPublishService notificationPublishService,
65             @Reference NetworkModelService networkModelService) {
66         this.pceServiceWrapper = new PCEServiceWrapper(pathComputationService, notificationPublishService);
67         setServiceInput(null);
68         setTempService(false);
69         this.notificationPublishService = notificationPublishService;
70         this.networkModelService = networkModelService;
71     }
72
73     @Override
74     public void onRendererRpcResultSp(RendererRpcResultSp notification) {
75         if (compareServiceRpcResultSp(notification)) {
76             LOG.warn("ServiceRpcResultSp already wired !");
77             return;
78         }
79         serviceRpcResultSp = notification;
80         int notifType = serviceRpcResultSp.getNotificationType().getIntValue();
81         LOG.info("Renderer '{}' Notification received : {}", serviceRpcResultSp.getNotificationType().getName(),
82                 notification);
83         switch (notifType) {
84             /* service-implementation-request. */
85             case 3:
86                 onServiceImplementationResult(notification);
87                 break;
88             /* service-delete. */
89             case 4:
90                 onServiceDeleteResult(notification);
91                 break;
92             default:
93                 break;
94         }
95     }
96
97     /**
98      * Process service delete result for serviceName.
99      * @param notification RendererRpcResultSp
100      */
101     private void onServiceDeleteResult(RendererRpcResultSp notification) {
102         switch (serviceRpcResultSp.getStatus()) {
103             case Successful:
104                 updateOtnTopology(notification, true);
105                 break;
106             case Failed:
107                 LOG.error("Renderer service delete failed !");
108                 Services service = serviceDataStoreOperations.getService(input.getServiceName()).get();
109                 sendNbiNotification(new PublishNotificationProcessServiceBuilder()
110                         .setServiceName(service.getServiceName())
111                         .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
112                         .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
113                         .setCommonId(service.getCommonId())
114                         .setConnectionType(service.getConnectionType())
115                         .setResponseFailed("Renderer service delete failed !")
116                         .setMessage("ServiceDelete request failed ...")
117                         .setOperationalState(service.getOperationalState())
118                         .setPublisherName(PUBLISHER)
119                         .build());
120                 return;
121             case Pending:
122                 LOG.warn("Renderer service delete returned a Pending RpcStatusEx code!");
123                 return;
124             default:
125                 LOG.error("Renderer service delete returned an unknown RpcStatusEx code!");
126                 return;
127         }
128         LOG.info("Service '{}' deleted !", notification.getServiceName());
129         if (this.input == null) {
130             LOG.error("ServiceInput parameter is null !");
131             return;
132         }
133         LOG.info("sending PCE cancel resource reserve for '{}'", this.input.getServiceName());
134         this.pceServiceWrapper.cancelPCEResource(this.input.getServiceName(),
135                 ServiceNotificationTypes.ServiceDeleteResult);
136         sendServiceHandlerNotification(notification, ServiceNotificationTypes.ServiceDeleteResult);
137     }
138
139     /**
140      * Process service implementation result for serviceName.
141      * @param notification RendererRpcResultSp
142      */
143     private void onServiceImplementationResult(RendererRpcResultSp notification) {
144         switch (serviceRpcResultSp.getStatus()) {
145             case Successful:
146                 onSuccededServiceImplementation(notification);
147                 break;
148             case Failed:
149                 onFailedServiceImplementation(notification.getServiceName());
150                 break;
151             case Pending:
152                 LOG.warn("Service Implementation still pending according to RpcStatusEx");
153                 break;
154             default:
155                 LOG.warn("Service Implementation has an unknown RpcStatusEx code");
156                 break;
157         }
158     }
159
160     /**
161      * Process succeeded service implementation for service.
162      * @param notification RendererRpcResultSp
163      */
164     private void onSuccededServiceImplementation(RendererRpcResultSp notification) {
165         LOG.info("Service implemented !");
166         if (serviceDataStoreOperations == null) {
167             LOG.debug("serviceDataStoreOperations is null");
168             return;
169         }
170
171         updateOtnTopology(notification, false);
172
173         PublishNotificationProcessServiceBuilder nbiNotificationBuilder = new PublishNotificationProcessServiceBuilder()
174                 .setServiceName(input.getServiceName())
175                 .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
176                 .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
177                 .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType())
178                 .setPublisherName(PUBLISHER);
179         OperationResult operationResult;
180         String serviceTemp = "";
181         if (tempService) {
182             operationResult = this.serviceDataStoreOperations.modifyTempService(
183                     serviceRpcResultSp.getServiceName(), State.InService, AdminStates.InService);
184             serviceTemp = "Temp ";
185         } else {
186             operationResult = this.serviceDataStoreOperations.modifyService(
187                     serviceRpcResultSp.getServiceName(), State.InService, AdminStates.InService);
188         }
189         if (operationResult.isSuccess()) {
190             sendNbiNotification(nbiNotificationBuilder
191                     .setResponseFailed("")
192                     .setMessage("Service implemented !")
193                     .setOperationalState(State.InService)
194                     .build());
195             if (!tempService) {
196                 sendServiceHandlerNotification(notification, ServiceNotificationTypes.ServiceCreateResult);
197             }
198         } else {
199             LOG.warn("{}Service status not updated in datastore !", serviceTemp);
200             sendNbiNotification(nbiNotificationBuilder
201                     .setResponseFailed(serviceTemp + "Service status not updated in datastore !")
202                     .setMessage("ServiceCreate request failed ...")
203                     .setOperationalState(State.OutOfService)
204                     .build());
205         }
206     }
207
208     /**
209      * Create and send service handler notification.
210      * @param notification RendererRpcResultSp
211      * @param type ServiceNotificationTypes
212      */
213     private void sendServiceHandlerNotification(RendererRpcResultSp notification, ServiceNotificationTypes type) {
214         try {
215             ServiceRpcResultSh serviceHandlerNotification = new ServiceRpcResultShBuilder()
216                     .setAToZDirection(notification.getAToZDirection())
217                     .setZToADirection(notification.getZToADirection())
218                     .setServiceName(notification.getServiceName())
219                     .setStatus(notification.getStatus())
220                     .setStatusMessage(notification.getStatusMessage())
221                     .setNotificationType(type)
222                     .build();
223             LOG.debug("Service update in datastore OK, sending notification {}", serviceHandlerNotification);
224             notificationPublishService.putNotification(
225                     serviceHandlerNotification);
226         } catch (InterruptedException e) {
227             LOG.warn("Something went wrong while sending notification for service {}",
228                     serviceRpcResultSp.getServiceName(), e);
229             Thread.currentThread().interrupt();
230         }
231     }
232
233     /**
234      * Process failed service implementation for serviceName.
235      * @param serviceName String
236      */
237     private void onFailedServiceImplementation(String serviceName) {
238         LOG.error("Renderer implementation failed !");
239         Services service = serviceDataStoreOperations.getService(input.getServiceName()).get();
240         sendNbiNotification(new PublishNotificationProcessServiceBuilder()
241                 .setServiceName(service.getServiceName())
242                 .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
243                 .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
244                 .setCommonId(service.getCommonId())
245                 .setConnectionType(service.getConnectionType())
246                 .setResponseFailed("Renderer implementation failed !")
247                 .setMessage("ServiceCreate request failed ...")
248                 .setOperationalState(service.getOperationalState())
249                 .setPublisherName(PUBLISHER)
250                 .build());
251         OperationResult deleteServicePathOperationResult =
252                 this.serviceDataStoreOperations.deleteServicePath(serviceName);
253         if (!deleteServicePathOperationResult.isSuccess()) {
254             LOG.warn("Service path was not removed from datastore!");
255         }
256         OperationResult deleteServiceOperationResult;
257         String serviceType = "";
258         if (tempService) {
259             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteTempService(serviceName);
260             serviceType = "Temp ";
261         } else {
262             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteService(serviceName);
263         }
264         if (deleteServiceOperationResult.isSuccess()) {
265             LOG.warn("{}Service was not removed from datastore!", serviceType);
266         }
267     }
268
269     @SuppressFBWarnings(
270         value = "ES_COMPARING_STRINGS_WITH_EQ",
271         justification = "false positives, not strings but real object references comparisons")
272     private Boolean compareServiceRpcResultSp(RendererRpcResultSp notification) {
273         if (serviceRpcResultSp == null
274                 || serviceRpcResultSp.getNotificationType() != notification.getNotificationType()
275                 || serviceRpcResultSp.getServiceName() != notification.getServiceName()
276                 || serviceRpcResultSp.getStatus() != notification.getStatus()
277                 || serviceRpcResultSp.getStatusMessage() != notification.getStatusMessage()) {
278             return false;
279         }
280         return true;
281     }
282
283     @Override
284     public void setServiceInput(ServiceInput serviceInput) {
285         this.input = serviceInput;
286     }
287
288     @Override
289     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
290         this.serviceDataStoreOperations = serviceData;
291     }
292
293     @Override
294     public void setTempService(Boolean tempService) {
295         this.tempService = tempService;
296     }
297
298     /**
299      * Send notification to NBI notification in order to publish message.
300      * @param service PublishNotificationService
301      */
302     private void sendNbiNotification(PublishNotificationProcessService service) {
303         try {
304             notificationPublishService.putNotification(service);
305         } catch (InterruptedException e) {
306             LOG.warn("Cannot send notification to nbi", e);
307             Thread.currentThread().interrupt();
308         }
309     }
310
311
312     private void updateOtnTopology(RendererRpcResultSp notification, boolean isDeletion) {
313         Link link = notification.getLink();
314         if (link == null && notification.getLinkId() == null) {
315             return;
316         }
317         List<String> supportedLinkIds = null;
318         if (notification.getLinkId() != null) {
319             supportedLinkIds = new ArrayList<>(notification.getLinkId());
320         }
321         String serviceType = notification.getServiceType();
322         switch (serviceType) {
323             case StringConstants.SERVICE_TYPE_OTU4:
324             case StringConstants.SERVICE_TYPE_OTUC2:
325             case StringConstants.SERVICE_TYPE_OTUC3:
326             case StringConstants.SERVICE_TYPE_OTUC4:
327             case StringConstants.SERVICE_TYPE_ODU4:
328             case StringConstants.SERVICE_TYPE_ODUC2:
329             case StringConstants.SERVICE_TYPE_ODUC3:
330             case StringConstants.SERVICE_TYPE_ODUC4:
331                 Map<String, OtnLinkType> otnLinkTypeMap = Map.of(
332                     StringConstants.SERVICE_TYPE_OTU4, OtnLinkType.OTU4,
333                     // TODO: need to change it when OtnLinkType is updated with enum
334                     StringConstants.SERVICE_TYPE_OTUC2, OtnLinkType.OTUC4,
335                     StringConstants.SERVICE_TYPE_OTUC3, OtnLinkType.OTUC4,
336                     StringConstants.SERVICE_TYPE_OTUC4, OtnLinkType.OTUC4,
337                     StringConstants.SERVICE_TYPE_ODU4, OtnLinkType.ODTU4,
338                     // TODO: need to change it when OtnLinkType is updated with enum
339                     StringConstants.SERVICE_TYPE_ODUC2, OtnLinkType.ODUC4,
340                     StringConstants.SERVICE_TYPE_ODUC3, OtnLinkType.ODUC4,
341                     StringConstants.SERVICE_TYPE_ODUC4, OtnLinkType.ODUC4);
342                 if (isDeletion) {
343                     LOG.info("updating otn-topology removing links");
344                     this.networkModelService.deleteOtnLinks(link, supportedLinkIds, otnLinkTypeMap.get(serviceType));
345                 } else {
346                     LOG.info("updating otn-topology adding links");
347                     this.networkModelService.createOtnLinks(link, supportedLinkIds, otnLinkTypeMap.get(serviceType));
348                 }
349                 break;
350             case StringConstants.SERVICE_TYPE_1GE:
351             case StringConstants.SERVICE_TYPE_10GE:
352             case StringConstants.SERVICE_TYPE_100GE_M:
353                 Short tribPort = Short.valueOf(notification.getAToZDirection().getMinTribSlot().getValue()
354                     .split("\\.")[0]);
355                 Short minTribSlot = Short.valueOf(notification.getAToZDirection().getMinTribSlot().getValue()
356                     .split("\\.")[1]);
357                 Short maxTribSlot = Short.valueOf(notification.getAToZDirection().getMaxTribSlot().getValue()
358                     .split("\\.")[1]);
359                 LOG.info("updating otn-topology node tps -tps and tpn pools");
360                 this.networkModelService.updateOtnLinks(link, supportedLinkIds,
361                     notification.getAToZDirection().getRate(), tribPort, minTribSlot, maxTribSlot, isDeletion);
362                 break;
363             case StringConstants.SERVICE_TYPE_100GE_S:
364                 this.networkModelService.updateOtnLinks(supportedLinkIds, isDeletion);
365                 break;
366             default:
367                 LOG.warn("service-type {} not managed yet", serviceType);
368                 break;
369         }
370     }
371
372 }