Migrate servicehandler module to OSGI DS
[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         if (!checkStatus(notification)) {
100             return;
101         }
102         if (servicePathRpcResult.getPathDescription() == null) {
103             LOG.error("'PathDescription' parameter is null ");
104             return;
105         }
106         PathDescription pathDescription =
107             new PathDescriptionBuilder()
108                 .setAToZDirection(servicePathRpcResult.getPathDescription().getAToZDirection())
109                 .setZToADirection(servicePathRpcResult.getPathDescription().getZToADirection())
110                 .build();
111         LOG.info("PathDescription gets : {}", pathDescription);
112         if (serviceFeasiblity) {
113             LOG.warn("service-feasibility-check RPC ");
114             return;
115         }
116         if (input == null) {
117             LOG.error("Input is null !");
118             return;
119         }
120         OperationResult operationResult = null;
121         if (tempService) {
122             operationResult = this.serviceDataStoreOperations.createTempService(input.getTempServiceCreateInput());
123             if (!operationResult.isSuccess()) {
124                 LOG.error("Temp Service not created in datastore !");
125             }
126         } else {
127             operationResult = this.serviceDataStoreOperations.createService(input.getServiceCreateInput());
128             if (!operationResult.isSuccess()) {
129                 LOG.error("Service not created in datastore !");
130             }
131         }
132         if (!this.serviceDataStoreOperations
133                 .createServicePath(
134                     input,
135                     //pceResponse
136                     new PathComputationRequestOutputBuilder()
137                         .setResponseParameters(
138                             new ResponseParametersBuilder()
139                                 .setPathDescription(
140                                     new org.opendaylight.yang.gen.v1
141                                             .http.org.transportpce.b.c._interface.service.types.rev220118
142                                                 .response.parameters.sp.response.parameters
143                                                     .PathDescriptionBuilder(pathDescription)
144                                         .build())
145                                 .build())
146                         .build())
147                 .isSuccess()) {
148             LOG.error("Service Path not created in datastore !");
149         }
150         ServiceImplementationRequestInput serviceImplementationRequest =
151             ModelMappingUtils.createServiceImplementationRequest(input, pathDescription);
152         LOG.info("Sending serviceImplementation request : {}", serviceImplementationRequest);
153         this.rendererServiceOperations.serviceImplementation(serviceImplementationRequest);
154     }
155
156     /**
157      * Check status of notification and send nbi notification.
158      * @param notification ServicePathRpcResult the notification to check.
159      * @return true is status is Successful, false otherwise.
160      */
161     private boolean checkStatus(ServicePathRpcResult notification) {
162         PublishNotificationProcessService nbiNotification = getPublishNotificationProcessService(notification);
163         PublishNotificationProcessServiceBuilder publishNotificationProcessServiceBuilder =
164                 new PublishNotificationProcessServiceBuilder(nbiNotification);
165         //TODO is it worth to instantiate the 2 variables above if status is 'Pending' or 'Successful' ?
166         switch (servicePathRpcResult.getStatus()) {
167             case Failed:
168                 LOG.error("PCE path computation failed !");
169                 nbiNotification = publishNotificationProcessServiceBuilder
170                         .setMessage("ServiceCreate request failed ...")
171                         .setResponseFailed("PCE path computation failed !")
172                         .setOperationalState(State.Degraded).build();
173                 sendNbiNotification(nbiNotification);
174                 return false;
175             case Pending:
176                 LOG.warn("PCE path computation returned a Pending RpcStatusEx code!");
177                 return false;
178             case Successful:
179                 LOG.info("PCE calculation done OK !");
180                 return true;
181             default:
182                 LOG.error("PCE path computation returned an unknown RpcStatusEx code {}",
183                         servicePathRpcResult.getStatus());
184                 nbiNotification = publishNotificationProcessServiceBuilder
185                         .setMessage("ServiceCreate request failed ...")
186                         .setResponseFailed("PCE path computation returned an unknown RpcStatusEx code!")
187                         .setOperationalState(State.Degraded).build();
188                 sendNbiNotification(nbiNotification);
189                 return false;
190         }
191     }
192
193     private PublishNotificationProcessService getPublishNotificationProcessService(ServicePathRpcResult notification) {
194         if (input == null) {
195             return new PublishNotificationProcessServiceBuilder()
196                 .setServiceName(notification.getServiceName())
197                 .setPublisherName(PUBLISHER)
198                 .build();
199         }
200         return new PublishNotificationProcessServiceBuilder()
201             .setServiceName(input.getServiceName())
202             .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
203             .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
204             .setCommonId(input.getCommonId())
205             .setConnectionType(input.getConnectionType())
206             .setPublisherName(PUBLISHER)
207             .build();
208     }
209
210     /**
211      * Process cancel resource result.
212      */
213     private void onCancelResourceResult() {
214         if (servicePathRpcResult.getStatus() == RpcStatusEx.Pending) {
215             LOG.warn("PCE cancel returned a Pending RpcStatusEx code !");
216             return;
217         } else if (servicePathRpcResult.getStatus() != RpcStatusEx.Successful
218                 && servicePathRpcResult.getStatus() != RpcStatusEx.Failed) {
219             LOG.error("PCE cancel returned an unknown RpcStatusEx code !");
220             return;
221         }
222         Services service = serviceDataStoreOperations.getService(input.getServiceName()).get();
223         PublishNotificationProcessServiceBuilder nbiNotificationBuilder =
224             new PublishNotificationProcessServiceBuilder()
225                 .setServiceName(service.getServiceName())
226                 .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
227                 .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
228                 .setCommonId(service.getCommonId())
229                 .setConnectionType(service.getConnectionType())
230                 .setPublisherName(PUBLISHER);
231         if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
232             LOG.info("PCE cancel resource failed !");
233             sendNbiNotification(
234                 nbiNotificationBuilder
235                     .setResponseFailed("PCE cancel resource failed !")
236                     .setMessage("ServiceDelete request failed ...")
237                     .setOperationalState(service.getOperationalState())
238                     .build());
239             return;
240         }
241         LOG.info("PCE cancel resource done OK !");
242         OperationResult deleteServicePathOperationResult =
243                 this.serviceDataStoreOperations.deleteServicePath(input.getServiceName());
244         if (!deleteServicePathOperationResult.isSuccess()) {
245             LOG.warn("Service path was not removed from datastore !");
246         }
247         OperationResult deleteServiceOperationResult;
248         String serviceType = "";
249         if (tempService) {
250             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteTempService(input.getServiceName());
251             serviceType = "Temp ";
252         } else {
253             deleteServiceOperationResult = this.serviceDataStoreOperations.deleteService(input.getServiceName());
254         }
255         if (deleteServiceOperationResult.isSuccess()) {
256             sendNbiNotification(
257                 nbiNotificationBuilder
258                     .setResponseFailed("")
259                     .setMessage("Service deleted !")
260                     .setOperationalState(State.Degraded)
261                     .build());
262         } else {
263             LOG.warn("{}Service was not removed from datastore !", serviceType);
264             sendNbiNotification(
265                 nbiNotificationBuilder
266                     .setResponseFailed(serviceType + "Service was not removed from datastore !")
267                     .setMessage("ServiceDelete request failed ...")
268                     .setOperationalState(service.getOperationalState())
269                     .build());
270         }
271         /**
272          * if it was an RPC serviceReconfigure, re-launch PCR.
273          */
274         if (this.serviceReconfigure) {
275             LOG.info("cancel resource reserve done, relaunching PCE path computation ...");
276             this.pceServiceWrapper.performPCE(input.getServiceCreateInput(), true);
277             this.serviceReconfigure = false;
278         }
279     }
280
281     @SuppressFBWarnings(
282         value = "ES_COMPARING_STRINGS_WITH_EQ",
283         justification = "false positives, not strings but real object references comparisons")
284     private Boolean compareServicePathRpcResult(ServicePathRpcResult notification) {
285         if (servicePathRpcResult == null) {
286             return false;
287         }
288         if (servicePathRpcResult.getNotificationType() != notification.getNotificationType()) {
289             return false;
290         }
291         if (servicePathRpcResult.getServiceName() != notification.getServiceName()) {
292             return false;
293         }
294         if (servicePathRpcResult.getStatus() != notification.getStatus()) {
295             return false;
296         }
297         if (servicePathRpcResult.getStatusMessage() != notification.getStatusMessage()) {
298             return false;
299         }
300         return true;
301     }
302
303     @Override
304     public void setInput(ServiceInput serviceInput) {
305         this.input = serviceInput;
306     }
307
308     @Override
309     public void setServiceReconfigure(Boolean serv) {
310         this.serviceReconfigure = serv;
311     }
312
313     @Override
314     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
315         this.serviceDataStoreOperations = serviceData;
316     }
317
318     @Override
319     public void setTempService(Boolean tempService) {
320         this.tempService = tempService;
321     }
322
323     @Override
324     public void setServiceFeasiblity(Boolean serviceFeasiblity) {
325         this.serviceFeasiblity = serviceFeasiblity;
326     }
327
328     /**
329      * Send notification to NBI notification in order to publish message.
330      * @param service PublishNotificationService
331      */
332     private void sendNbiNotification(PublishNotificationProcessService service) {
333         try {
334             notificationPublishService.putNotification(service);
335         } catch (InterruptedException e) {
336             LOG.warn("Cannot send notification to nbi", e);
337             Thread.currentThread().interrupt();
338         }
339     }
340 }