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