Fix bugs in nbinotifications module
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / listeners / PceNotificationHandler.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.Set;
12 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
13 import org.opendaylight.mdsal.binding.api.NotificationService.CompositeListener;
14 import org.opendaylight.transportpce.common.OperationResult;
15 import org.opendaylight.transportpce.pce.service.PathComputationService;
16 import org.opendaylight.transportpce.renderer.provisiondevice.RendererServiceOperations;
17 import org.opendaylight.transportpce.servicehandler.ModelMappingUtils;
18 import org.opendaylight.transportpce.servicehandler.ServiceInput;
19 import org.opendaylight.transportpce.servicehandler.service.PCEServiceWrapper;
20 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
21 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestOutputBuilder;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.ServicePathRpcResult;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.service.path.rpc.result.PathDescription;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.service.path.rpc.result.PathDescriptionBuilder;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
28 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
29 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
30 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.PublishNotificationProcessService;
31 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.PublishNotificationProcessServiceBuilder;
32 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.notification.process.service.ServiceAEndBuilder;
33 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.notification.process.service.ServiceZEndBuilder;
34 import org.osgi.service.component.annotations.Activate;
35 import org.osgi.service.component.annotations.Component;
36 import org.osgi.service.component.annotations.Reference;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 @Component(service = {PceNotificationHandler.class, PceListener.class})
41 public class PceNotificationHandler implements PceListener {
42
43     private static final Logger LOG = LoggerFactory.getLogger(PceNotificationHandler.class);
44     private static final String PUBLISHER = "PceListener";
45
46     private ServicePathRpcResult servicePathRpcResult;
47     private RendererServiceOperations rendererServiceOperations;
48     private ServiceDataStoreOperations serviceDataStoreOperations;
49     private PCEServiceWrapper pceServiceWrapper;
50     private ServiceInput input;
51     private Boolean serviceReconfigure;
52     private Boolean tempService;
53     private Boolean serviceFeasiblity;
54     private NotificationPublishService notificationPublishService;
55
56     @Activate
57     public PceNotificationHandler(
58             @Reference RendererServiceOperations rendererServiceOperations,
59             @Reference PathComputationService pathComputationService,
60             @Reference NotificationPublishService notificationPublishService,
61             @Reference ServiceDataStoreOperations serviceDataStoreOperations) {
62         this.rendererServiceOperations = rendererServiceOperations;
63         this.pceServiceWrapper = new PCEServiceWrapper(pathComputationService, notificationPublishService);
64         this.serviceDataStoreOperations = serviceDataStoreOperations;
65         setServiceReconfigure(false);
66         setInput(null);
67         setTempService(false);
68         setServiceFeasiblity(false);
69         this.notificationPublishService = notificationPublishService;
70     }
71
72     public CompositeListener getCompositeListener() {
73         return new CompositeListener(Set.of(
74             new CompositeListener.Component<>(ServicePathRpcResult.class, this::onServicePathRpcResult)));
75     }
76
77     private void onServicePathRpcResult(ServicePathRpcResult notification) {
78         if (compareServicePathRpcResult(notification)) {
79             LOG.warn("ServicePathRpcResult already wired !");
80             return;
81         }
82         servicePathRpcResult = notification;
83         switch (servicePathRpcResult.getNotificationType().getIntValue()) {
84             /* path-computation-request. */
85             case 1:
86                 onPathComputationResult(notification);
87                 break;
88             /* cancel-resource-reserve. */
89             case 2:
90                 onCancelResourceResult();
91                 break;
92             default:
93                 break;
94         }
95     }
96
97     /**
98      * Process path computation request result.
99      * @param notification the result notification.
100      */
101     private void onPathComputationResult(ServicePathRpcResult notification) {
102         LOG.info("PCE '{}' Notification received : {}", servicePathRpcResult.getNotificationType().getName(),
103                 notification);
104
105         if (!checkStatus(notification)) {
106             return;
107         }
108         if (servicePathRpcResult.getPathDescription() == null) {
109             LOG.error("'PathDescription' parameter is null ");
110             return;
111         }
112         PathDescription pathDescription =
113             new PathDescriptionBuilder()
114                 .setAToZDirection(servicePathRpcResult.getPathDescription().getAToZDirection())
115                 .setZToADirection(servicePathRpcResult.getPathDescription().getZToADirection())
116                 .build();
117         LOG.info("PathDescription gets : {}", pathDescription);
118         if (serviceFeasiblity) {
119             LOG.warn("service-feasibility-check RPC ");
120             return;
121         }
122         if (input == null) {
123             LOG.error("Input is null !");
124             return;
125         }
126         OperationResult operationResult = null;
127         if (tempService) {
128             operationResult =
129                     this.serviceDataStoreOperations.createTempService(
130                             input.getTempServiceCreateInput(), pathDescription);
131             if (!operationResult.isSuccess()) {
132                 LOG.error("Temp Service not created in datastore !");
133             }
134         } else {
135             operationResult = this.serviceDataStoreOperations.createService(input.getServiceCreateInput());
136             if (!operationResult.isSuccess()) {
137                 LOG.error("Service not created in datastore !");
138             }
139         }
140         if (!this.serviceDataStoreOperations
141                 .createServicePath(
142                     input,
143                     //pceResponse
144                     new PathComputationRequestOutputBuilder()
145                         .setResponseParameters(
146                             new ResponseParametersBuilder()
147                                 .setPathDescription(
148                                     new org.opendaylight.yang.gen.v1
149                                             .http.org.transportpce.b.c._interface.service.types.rev220118
150                                                 .response.parameters.sp.response.parameters
151                                                     .PathDescriptionBuilder(pathDescription)
152                                         .build())
153                                 .build())
154                         .build())
155                 .isSuccess()) {
156             LOG.error("Service Path not created in datastore !");
157         }
158         ServiceImplementationRequestInput serviceImplementationRequest =
159             ModelMappingUtils.createServiceImplementationRequest(input, pathDescription);
160         LOG.info("Sending serviceImplementation request : {}", serviceImplementationRequest);
161         LOG.debug("Temp-service value is {}", tempService);
162         this.rendererServiceOperations.serviceImplementation(serviceImplementationRequest, tempService);
163     }
164
165     /**
166      * Check status of notification and send nbi notification.
167      * @param notification ServicePathRpcResult the notification to check.
168      * @return true is status is Successful, false otherwise.
169      */
170     private boolean checkStatus(ServicePathRpcResult notification) {
171         PublishNotificationProcessService nbiNotification = getPublishNotificationProcessService(notification);
172         PublishNotificationProcessServiceBuilder publishNotificationProcessServiceBuilder =
173                 new PublishNotificationProcessServiceBuilder(nbiNotification);
174         //TODO is it worth to instantiate the 2 variables above if status is 'Pending' or 'Successful' ?
175         switch (servicePathRpcResult.getStatus()) {
176             case Failed:
177                 LOG.error("PCE path computation failed !");
178                 nbiNotification = publishNotificationProcessServiceBuilder
179                         .setMessage("ServiceCreate request failed ...")
180                         .setResponseFailed("PCE path computation failed !")
181                         .setOperationalState(State.Degraded).build();
182                 sendNbiNotification(nbiNotification);
183                 return false;
184             case Pending:
185                 LOG.warn("PCE path computation returned a Pending RpcStatusEx code!");
186                 return false;
187             case Successful:
188                 LOG.info("PCE calculation done OK !");
189                 return true;
190             default:
191                 LOG.error("PCE path computation returned an unknown RpcStatusEx code {}",
192                         servicePathRpcResult.getStatus());
193                 nbiNotification = publishNotificationProcessServiceBuilder
194                         .setMessage("ServiceCreate request failed ...")
195                         .setResponseFailed("PCE path computation returned an unknown RpcStatusEx code!")
196                         .setOperationalState(State.Degraded).build();
197                 sendNbiNotification(nbiNotification);
198                 return false;
199         }
200     }
201
202     private PublishNotificationProcessService getPublishNotificationProcessService(ServicePathRpcResult notification) {
203         if (input == null) {
204             return new PublishNotificationProcessServiceBuilder()
205                 .setServiceName(notification.getServiceName())
206                 .setPublisherName(PUBLISHER)
207                 .build();
208         }
209         return new PublishNotificationProcessServiceBuilder()
210             .setServiceName(input.getServiceName())
211             .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
212             .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
213             .setCommonId(input.getCommonId())
214             .setConnectionType(input.getConnectionType())
215             .setPublisherName(PUBLISHER)
216             .build();
217     }
218
219     /**
220      * Process cancel resource result.
221      */
222     private void onCancelResourceResult() {
223         if (servicePathRpcResult.getStatus() == RpcStatusEx.Pending) {
224             LOG.warn("PCE cancel returned a Pending RpcStatusEx code !");
225             return;
226         } else if (servicePathRpcResult.getStatus() != RpcStatusEx.Successful
227                 && servicePathRpcResult.getStatus() != RpcStatusEx.Failed) {
228             LOG.error("PCE cancel returned an unknown RpcStatusEx code !");
229             return;
230         }
231         PublishNotificationProcessServiceBuilder nbiNotificationBuilder;
232         State serviceOpState;
233         if (tempService) {
234             org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.temp.service.list.Services
235                     tempServiceList = serviceDataStoreOperations.getTempService(input.getServiceName()).orElseThrow();
236             serviceOpState = tempServiceList.getOperationalState();
237             nbiNotificationBuilder =
238                     new PublishNotificationProcessServiceBuilder()
239                             .setServiceAEnd(new ServiceAEndBuilder(tempServiceList.getServiceAEnd()).build())
240                             .setServiceZEnd(new ServiceZEndBuilder(tempServiceList.getServiceZEnd()).build())
241                             .setCommonId(tempServiceList.getCommonId())
242                             .setConnectionType(tempServiceList.getConnectionType())
243                             .setIsTempService(true)
244                             .setPublisherName(PUBLISHER);
245         } else {
246             Services service = serviceDataStoreOperations.getService(input.getServiceName()).orElseThrow();
247             serviceOpState = service.getOperationalState();
248             nbiNotificationBuilder =
249                     new PublishNotificationProcessServiceBuilder()
250                             .setServiceName(service.getServiceName())
251                             .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
252                             .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
253                             .setCommonId(service.getCommonId())
254                             .setIsTempService(false)
255                             .setConnectionType(service.getConnectionType())
256                             .setPublisherName(PUBLISHER);
257
258         }
259
260         if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
261             LOG.info("PCE cancel resource failed !");
262             sendNbiNotification(
263                 nbiNotificationBuilder
264                     .setResponseFailed("PCE cancel resource failed !")
265                     .setMessage("ServiceDelete request failed ...")
266                     .setOperationalState(serviceOpState)
267                     .build());
268             return;
269         }
270         LOG.info("PCE cancel resource done OK !");
271         // Here the input refers to the transportPCE API and the serviceName will be commonId for temp-service
272         OperationResult deleteServicePathOperationResult =
273                 this.serviceDataStoreOperations.deleteServicePath(input.getServiceName());
274         if (!deleteServicePathOperationResult.isSuccess()) {
275             LOG.warn("Service path was not removed from datastore !");
276         }
277         OperationResult deleteServiceOperationResult;
278         String serviceType = "";
279         if (tempService) {
280             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteTempService(input.getServiceName());
281             serviceType = "Temp ";
282         } else {
283             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteService(input.getServiceName());
284         }
285         if (deleteServiceOperationResult.isSuccess()) {
286             sendNbiNotification(
287                 nbiNotificationBuilder
288                     .setResponseFailed("")
289                     .setMessage("Service deleted !")
290                     .setOperationalState(State.Degraded)
291                     .build());
292         } else {
293             LOG.warn("{} Service was not removed from datastore !", serviceType);
294             sendNbiNotification(
295                 nbiNotificationBuilder
296                     .setResponseFailed(serviceType + "Service was not removed from datastore !")
297                     .setMessage("ServiceDelete request failed ...")
298                     .setOperationalState(serviceOpState)
299                     .build());
300         }
301         // TODO: should we re-initialize the temp-service boolean to false?
302         /**
303          * if it was an RPC serviceReconfigure, re-launch PCR.
304          */
305         if (this.serviceReconfigure) {
306             LOG.info("cancel resource reserve done, relaunching PCE path computation ...");
307             this.pceServiceWrapper.performPCE(input.getServiceCreateInput(), true);
308             this.serviceReconfigure = false;
309         }
310     }
311
312     @SuppressFBWarnings(
313         value = "ES_COMPARING_STRINGS_WITH_EQ",
314         justification = "false positives, not strings but real object references comparisons")
315     private Boolean compareServicePathRpcResult(ServicePathRpcResult notification) {
316         if (servicePathRpcResult == null) {
317             return false;
318         }
319         if (servicePathRpcResult.getNotificationType() != notification.getNotificationType()) {
320             return false;
321         }
322         if (servicePathRpcResult.getServiceName() != notification.getServiceName()) {
323             return false;
324         }
325         if (servicePathRpcResult.getStatus() != notification.getStatus()) {
326             return false;
327         }
328         if (servicePathRpcResult.getStatusMessage() != notification.getStatusMessage()) {
329             return false;
330         }
331         return true;
332     }
333
334     @Override
335     public void setInput(ServiceInput serviceInput) {
336         this.input = serviceInput;
337     }
338
339     @Override
340     public void setServiceReconfigure(Boolean serv) {
341         this.serviceReconfigure = serv;
342     }
343
344     @Override
345     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
346         this.serviceDataStoreOperations = serviceData;
347     }
348
349     @Override
350     public void setTempService(Boolean tempService) {
351         this.tempService = tempService;
352     }
353
354     @Override
355     public void setServiceFeasiblity(Boolean serviceFeasiblity) {
356         this.serviceFeasiblity = serviceFeasiblity;
357     }
358
359     /**
360      * Send notification to NBI notification in order to publish message.
361      * @param service PublishNotificationService
362      */
363     private void sendNbiNotification(PublishNotificationProcessService service) {
364         try {
365             notificationPublishService.putNotification(service);
366         } catch (InterruptedException e) {
367             LOG.warn("Cannot send notification to nbi", e);
368             Thread.currentThread().interrupt();
369         }
370     }
371 }