8d1b4a35f226a23511543b5e96269997503013c6
[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.rev211210.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         this.rendererServiceOperations.serviceImplementation(serviceImplementationRequest);
157     }
158
159     /**
160      * Check status of notification and send nbi notification.
161      * @param notification ServicePathRpcResult the notification to check.
162      * @return true is status is Successful, false otherwise.
163      */
164     private boolean checkStatus(ServicePathRpcResult notification) {
165         PublishNotificationProcessService nbiNotification = getPublishNotificationProcessService(notification);
166         PublishNotificationProcessServiceBuilder publishNotificationProcessServiceBuilder =
167                 new PublishNotificationProcessServiceBuilder(nbiNotification);
168         //TODO is it worth to instantiate the 2 variables above if status is 'Pending' or 'Successful' ?
169         switch (servicePathRpcResult.getStatus()) {
170             case Failed:
171                 LOG.error("PCE path computation failed !");
172                 nbiNotification = publishNotificationProcessServiceBuilder
173                         .setMessage("ServiceCreate request failed ...")
174                         .setResponseFailed("PCE path computation failed !")
175                         .setOperationalState(State.Degraded).build();
176                 sendNbiNotification(nbiNotification);
177                 return false;
178             case Pending:
179                 LOG.warn("PCE path computation returned a Pending RpcStatusEx code!");
180                 return false;
181             case Successful:
182                 LOG.info("PCE calculation done OK !");
183                 return true;
184             default:
185                 LOG.error("PCE path computation returned an unknown RpcStatusEx code {}",
186                         servicePathRpcResult.getStatus());
187                 nbiNotification = publishNotificationProcessServiceBuilder
188                         .setMessage("ServiceCreate request failed ...")
189                         .setResponseFailed("PCE path computation returned an unknown RpcStatusEx code!")
190                         .setOperationalState(State.Degraded).build();
191                 sendNbiNotification(nbiNotification);
192                 return false;
193         }
194     }
195
196     private PublishNotificationProcessService getPublishNotificationProcessService(ServicePathRpcResult notification) {
197         if (input == null) {
198             return new PublishNotificationProcessServiceBuilder()
199                 .setServiceName(notification.getServiceName())
200                 .setPublisherName(PUBLISHER)
201                 .build();
202         }
203         return new PublishNotificationProcessServiceBuilder()
204             .setServiceName(input.getServiceName())
205             .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
206             .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
207             .setCommonId(input.getCommonId())
208             .setConnectionType(input.getConnectionType())
209             .setPublisherName(PUBLISHER)
210             .build();
211     }
212
213     /**
214      * Process cancel resource result.
215      */
216     private void onCancelResourceResult() {
217         if (servicePathRpcResult.getStatus() == RpcStatusEx.Pending) {
218             LOG.warn("PCE cancel returned a Pending RpcStatusEx code !");
219             return;
220         } else if (servicePathRpcResult.getStatus() != RpcStatusEx.Successful
221                 && servicePathRpcResult.getStatus() != RpcStatusEx.Failed) {
222             LOG.error("PCE cancel returned an unknown RpcStatusEx code !");
223             return;
224         }
225         Services service = serviceDataStoreOperations.getService(input.getServiceName()).orElseThrow();
226         PublishNotificationProcessServiceBuilder nbiNotificationBuilder =
227             new PublishNotificationProcessServiceBuilder()
228                 .setServiceName(service.getServiceName())
229                 .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
230                 .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
231                 .setCommonId(service.getCommonId())
232                 .setConnectionType(service.getConnectionType())
233                 .setPublisherName(PUBLISHER);
234         if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
235             LOG.info("PCE cancel resource failed !");
236             sendNbiNotification(
237                 nbiNotificationBuilder
238                     .setResponseFailed("PCE cancel resource failed !")
239                     .setMessage("ServiceDelete request failed ...")
240                     .setOperationalState(service.getOperationalState())
241                     .build());
242             return;
243         }
244         LOG.info("PCE cancel resource done OK !");
245         OperationResult deleteServicePathOperationResult =
246                 this.serviceDataStoreOperations.deleteServicePath(input.getServiceName());
247         if (!deleteServicePathOperationResult.isSuccess()) {
248             LOG.warn("Service path was not removed from datastore !");
249         }
250         OperationResult deleteServiceOperationResult;
251         String serviceType = "";
252         if (tempService) {
253             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteTempService(input.getServiceName());
254             serviceType = "Temp ";
255         } else {
256             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteService(input.getServiceName());
257         }
258         if (deleteServiceOperationResult.isSuccess()) {
259             sendNbiNotification(
260                 nbiNotificationBuilder
261                     .setResponseFailed("")
262                     .setMessage("Service deleted !")
263                     .setOperationalState(State.Degraded)
264                     .build());
265         } else {
266             LOG.warn("{}Service was not removed from datastore !", serviceType);
267             sendNbiNotification(
268                 nbiNotificationBuilder
269                     .setResponseFailed(serviceType + "Service was not removed from datastore !")
270                     .setMessage("ServiceDelete request failed ...")
271                     .setOperationalState(service.getOperationalState())
272                     .build());
273         }
274         /**
275          * if it was an RPC serviceReconfigure, re-launch PCR.
276          */
277         if (this.serviceReconfigure) {
278             LOG.info("cancel resource reserve done, relaunching PCE path computation ...");
279             this.pceServiceWrapper.performPCE(input.getServiceCreateInput(), true);
280             this.serviceReconfigure = false;
281         }
282     }
283
284     @SuppressFBWarnings(
285         value = "ES_COMPARING_STRINGS_WITH_EQ",
286         justification = "false positives, not strings but real object references comparisons")
287     private Boolean compareServicePathRpcResult(ServicePathRpcResult notification) {
288         if (servicePathRpcResult == null) {
289             return false;
290         }
291         if (servicePathRpcResult.getNotificationType() != notification.getNotificationType()) {
292             return false;
293         }
294         if (servicePathRpcResult.getServiceName() != notification.getServiceName()) {
295             return false;
296         }
297         if (servicePathRpcResult.getStatus() != notification.getStatus()) {
298             return false;
299         }
300         if (servicePathRpcResult.getStatusMessage() != notification.getStatusMessage()) {
301             return false;
302         }
303         return true;
304     }
305
306     @Override
307     public void setInput(ServiceInput serviceInput) {
308         this.input = serviceInput;
309     }
310
311     @Override
312     public void setServiceReconfigure(Boolean serv) {
313         this.serviceReconfigure = serv;
314     }
315
316     @Override
317     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
318         this.serviceDataStoreOperations = serviceData;
319     }
320
321     @Override
322     public void setTempService(Boolean tempService) {
323         this.tempService = tempService;
324     }
325
326     @Override
327     public void setServiceFeasiblity(Boolean serviceFeasiblity) {
328         this.serviceFeasiblity = serviceFeasiblity;
329     }
330
331     /**
332      * Send notification to NBI notification in order to publish message.
333      * @param service PublishNotificationService
334      */
335     private void sendNbiNotification(PublishNotificationProcessService service) {
336         try {
337             notificationPublishService.putNotification(service);
338         } catch (InterruptedException e) {
339             LOG.warn("Cannot send notification to nbi", e);
340             Thread.currentThread().interrupt();
341         }
342     }
343 }