Use version 13.1.0 of openroadm-service models
[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         Services service = serviceDataStoreOperations.getService(input.getServiceName()).orElseThrow();
227         PublishNotificationProcessServiceBuilder nbiNotificationBuilder =
228             new PublishNotificationProcessServiceBuilder()
229                 .setServiceName(service.getServiceName())
230                 .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
231                 .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
232                 .setCommonId(service.getCommonId())
233                 .setConnectionType(service.getConnectionType())
234                 .setPublisherName(PUBLISHER);
235         if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
236             LOG.info("PCE cancel resource failed !");
237             sendNbiNotification(
238                 nbiNotificationBuilder
239                     .setResponseFailed("PCE cancel resource failed !")
240                     .setMessage("ServiceDelete request failed ...")
241                     .setOperationalState(service.getOperationalState())
242                     .build());
243             return;
244         }
245         LOG.info("PCE cancel resource done OK !");
246         OperationResult deleteServicePathOperationResult =
247                 this.serviceDataStoreOperations.deleteServicePath(input.getServiceName());
248         if (!deleteServicePathOperationResult.isSuccess()) {
249             LOG.warn("Service path was not removed from datastore !");
250         }
251         OperationResult deleteServiceOperationResult;
252         String serviceType = "";
253         if (tempService) {
254             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteTempService(input.getServiceName());
255             serviceType = "Temp ";
256         } else {
257             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteService(input.getServiceName());
258         }
259         if (deleteServiceOperationResult.isSuccess()) {
260             sendNbiNotification(
261                 nbiNotificationBuilder
262                     .setResponseFailed("")
263                     .setMessage("Service deleted !")
264                     .setOperationalState(State.Degraded)
265                     .build());
266         } else {
267             LOG.warn("{}Service was not removed from datastore !", serviceType);
268             sendNbiNotification(
269                 nbiNotificationBuilder
270                     .setResponseFailed(serviceType + "Service was not removed from datastore !")
271                     .setMessage("ServiceDelete request failed ...")
272                     .setOperationalState(service.getOperationalState())
273                     .build());
274         }
275         /**
276          * if it was an RPC serviceReconfigure, re-launch PCR.
277          */
278         if (this.serviceReconfigure) {
279             LOG.info("cancel resource reserve done, relaunching PCE path computation ...");
280             this.pceServiceWrapper.performPCE(input.getServiceCreateInput(), true);
281             this.serviceReconfigure = false;
282         }
283     }
284
285     @SuppressFBWarnings(
286         value = "ES_COMPARING_STRINGS_WITH_EQ",
287         justification = "false positives, not strings but real object references comparisons")
288     private Boolean compareServicePathRpcResult(ServicePathRpcResult notification) {
289         if (servicePathRpcResult == null) {
290             return false;
291         }
292         if (servicePathRpcResult.getNotificationType() != notification.getNotificationType()) {
293             return false;
294         }
295         if (servicePathRpcResult.getServiceName() != notification.getServiceName()) {
296             return false;
297         }
298         if (servicePathRpcResult.getStatus() != notification.getStatus()) {
299             return false;
300         }
301         if (servicePathRpcResult.getStatusMessage() != notification.getStatusMessage()) {
302             return false;
303         }
304         return true;
305     }
306
307     @Override
308     public void setInput(ServiceInput serviceInput) {
309         this.input = serviceInput;
310     }
311
312     @Override
313     public void setServiceReconfigure(Boolean serv) {
314         this.serviceReconfigure = serv;
315     }
316
317     @Override
318     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
319         this.serviceDataStoreOperations = serviceData;
320     }
321
322     @Override
323     public void setTempService(Boolean tempService) {
324         this.tempService = tempService;
325     }
326
327     @Override
328     public void setServiceFeasiblity(Boolean serviceFeasiblity) {
329         this.serviceFeasiblity = serviceFeasiblity;
330     }
331
332     /**
333      * Send notification to NBI notification in order to publish message.
334      * @param service PublishNotificationService
335      */
336     private void sendNbiNotification(PublishNotificationProcessService service) {
337         try {
338             notificationPublishService.putNotification(service);
339         } catch (InterruptedException e) {
340             LOG.warn("Cannot send notification to nbi", e);
341             Thread.currentThread().interrupt();
342         }
343     }
344 }