04b71a9b227e23261274f68cc3d6785b6276945c
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / service / PCEServiceWrapper.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.service;
9
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.util.concurrent.Executors;
16 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
17 import org.opendaylight.transportpce.common.ResponseCodes;
18 import org.opendaylight.transportpce.pce.service.PathComputationService;
19 import org.opendaylight.transportpce.servicehandler.MappingConstraints;
20 import org.opendaylight.transportpce.servicehandler.ModelMappingUtils;
21 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.CancelResourceReserveInput;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.CancelResourceReserveInputBuilder;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.CancelResourceReserveOutput;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.CancelResourceReserveOutputBuilder;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.PathComputationRequestInput;
26 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.PathComputationRequestInputBuilder;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.PathComputationRequestOutput;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220118.PathComputationRequestOutputBuilder;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultSh;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultShBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ServiceEndpoint;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ServiceNotificationTypes;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.configuration.response.common.ConfigurationResponseCommon;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.configuration.response.common.ConfigurationResponseCommonBuilder;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.sdnc.request.header.SdncRequestHeader;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.ServiceCreateInput;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.ServiceFeasibilityCheckInput;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.TempServiceCreateInput;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev220118.routing.constraints.sp.HardConstraints;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev220118.routing.constraints.sp.SoftConstraints;
41 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.PceMetric;
42 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
43 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParameters;
44 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.handler.header.ServiceHandlerHeaderBuilder;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class PCEServiceWrapper {
50
51     private static final String NOTIFICATION_OFFER_REJECTED_MSG = "notification offer rejected : ";
52
53     private static final String PERFORMING_PCE_MSG = "performing PCE ...";
54
55     private static final Logger LOG = LoggerFactory.getLogger(PCEServiceWrapper.class);
56
57     private final PathComputationService pathComputationService;
58     private final NotificationPublishService notificationPublishService;
59     private ServiceRpcResultSh notification = null;
60     private final ListeningExecutorService executor;
61
62     public PCEServiceWrapper(PathComputationService pathComputationService,
63             NotificationPublishService notificationPublishService) {
64         this.pathComputationService = pathComputationService;
65         this.notificationPublishService = notificationPublishService;
66         executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
67     }
68
69     public PathComputationRequestOutput performPCE(ServiceCreateInput serviceCreateInput, boolean reserveResource) {
70         LOG.info(PERFORMING_PCE_MSG);
71         if (validateParams(serviceCreateInput.getServiceName(), serviceCreateInput.getSdncRequestHeader())) {
72             return performPCE(serviceCreateInput.getHardConstraints(), serviceCreateInput.getSoftConstraints(),
73                     serviceCreateInput.getServiceName(), serviceCreateInput.getSdncRequestHeader(),
74                     serviceCreateInput.getServiceAEnd(), serviceCreateInput.getServiceZEnd(),
75                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
76         } else {
77             return returnPCEFailed();
78         }
79     }
80
81     public PathComputationRequestOutput performPCE(TempServiceCreateInput tempServiceCreateInput,
82             boolean reserveResource) {
83         LOG.info(PERFORMING_PCE_MSG);
84         if (validateParams(tempServiceCreateInput.getCommonId(), tempServiceCreateInput.getSdncRequestHeader())) {
85             return performPCE(tempServiceCreateInput.getHardConstraints(), tempServiceCreateInput.getSoftConstraints(),
86                     tempServiceCreateInput.getCommonId(), tempServiceCreateInput.getSdncRequestHeader(),
87                     tempServiceCreateInput.getServiceAEnd(), tempServiceCreateInput.getServiceZEnd(),
88                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
89         } else {
90             return returnPCEFailed();
91         }
92     }
93
94     public PathComputationRequestOutput performPCE(ServiceFeasibilityCheckInput serviceFeasibilityCheckInput,
95             boolean reserveResource) {
96         LOG.info(PERFORMING_PCE_MSG);
97         if (validateParams(serviceFeasibilityCheckInput.getCommonId(),
98                 serviceFeasibilityCheckInput.getSdncRequestHeader())) {
99             return performPCE(serviceFeasibilityCheckInput.getHardConstraints(),
100                     serviceFeasibilityCheckInput.getSoftConstraints(), serviceFeasibilityCheckInput.getCommonId(),
101                     serviceFeasibilityCheckInput.getSdncRequestHeader(), serviceFeasibilityCheckInput.getServiceAEnd(),
102                     serviceFeasibilityCheckInput.getServiceZEnd(),
103                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
104         } else {
105             return returnPCEFailed();
106         }
107     }
108
109     private PathComputationRequestOutput performPCE(org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constrains
110             .rev190329.routing.constraints.HardConstraints hardConstraints, org.opendaylight.yang.gen.v1.http.org
111             .openroadm.routing.constrains.rev190329.routing.constraints.SoftConstraints softConstraints,
112             String serviceName, SdncRequestHeader sdncRequestHeader, ServiceEndpoint serviceAEnd,
113             ServiceEndpoint serviceZEnd, ServiceNotificationTypes notifType, boolean reserveResource) {
114         MappingConstraints mappingConstraints = new MappingConstraints(hardConstraints, softConstraints);
115         mappingConstraints.serviceToServicePathConstarints();
116         LOG.info("Calling path computation.");
117         notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
118                 .setStatus(RpcStatusEx.Pending)
119                 .setStatusMessage("Service compliant, submitting PathComputation Request ...").build();
120         try {
121             notificationPublishService.putNotification(notification);
122         } catch (InterruptedException e) {
123             LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
124         }
125         FutureCallback<PathComputationRequestOutput> pceCallback =
126                 new PathComputationRequestOutputCallback(notifType, serviceName);
127         PathComputationRequestInput pathComputationRequestInput = createPceRequestInput(serviceName, sdncRequestHeader,
128                 mappingConstraints.getServicePathHardConstraints(), mappingConstraints.getServicePathSoftConstraints(),
129                 reserveResource, serviceAEnd, serviceZEnd);
130         ListenableFuture<PathComputationRequestOutput> pce = this.pathComputationService
131                 .pathComputationRequest(pathComputationRequestInput);
132         Futures.addCallback(pce, pceCallback, executor);
133
134         ConfigurationResponseCommon configurationResponseCommon = new ConfigurationResponseCommonBuilder()
135                 .setAckFinalIndicator(ResponseCodes.FINAL_ACK_NO)
136                 .setRequestId(sdncRequestHeader.getRequestId())
137                 .setResponseCode(ResponseCodes.RESPONSE_OK)
138                 .setResponseMessage("PCE calculation in progress")
139                 .build();
140         ResponseParameters reponseParameters = new ResponseParametersBuilder().build();
141         return new PathComputationRequestOutputBuilder()
142                 .setConfigurationResponseCommon(configurationResponseCommon)
143                 .setResponseParameters(reponseParameters)
144                 .build();
145     }
146
147     private PathComputationRequestInput createPceRequestInput(String serviceName,
148             SdncRequestHeader serviceHandler, HardConstraints hardConstraints,
149             SoftConstraints softConstraints, Boolean reserveResource, ServiceEndpoint serviceAEnd,
150             ServiceEndpoint serviceZEnd) {
151         LOG.info("Mapping ServiceCreateInput or ServiceFeasibilityCheckInput or serviceReconfigureInput to PCE"
152                 + "requests");
153         ServiceHandlerHeaderBuilder serviceHandlerHeader = new ServiceHandlerHeaderBuilder();
154         if (serviceHandler != null) {
155             serviceHandlerHeader.setRequestId(serviceHandler.getRequestId());
156         }
157         return new PathComputationRequestInputBuilder()
158             .setServiceName(serviceName)
159             .setResourceReserve(reserveResource)
160             .setServiceHandlerHeader(serviceHandlerHeader.build())
161             .setHardConstraints(hardConstraints)
162             .setSoftConstraints(softConstraints)
163             .setPceRoutingMetric(PceMetric.TEMetric)
164             .setServiceAEnd(ModelMappingUtils.createServiceAEnd(serviceAEnd))
165             .setServiceZEnd(ModelMappingUtils.createServiceZEnd(serviceZEnd))
166             .build();
167     }
168
169     private CancelResourceReserveInput mappingCancelResourceReserve(String serviceName,
170                                                                     SdncRequestHeader sdncRequestHeader) {
171         LOG.info("Mapping to PCE Cancel resource request input");
172         CancelResourceReserveInputBuilder cancelResourceReserveInput = new CancelResourceReserveInputBuilder();
173         if (serviceName != null) {
174             ServiceHandlerHeaderBuilder serviceHandlerHeader = new ServiceHandlerHeaderBuilder();
175             if (sdncRequestHeader != null) {
176                 serviceHandlerHeader.setRequestId(sdncRequestHeader.getRequestId());
177             }
178             cancelResourceReserveInput.setServiceName(serviceName)
179                     .setServiceHandlerHeader(serviceHandlerHeader.build());
180             return cancelResourceReserveInput.build();
181         } else {
182             LOG.error("Service Name (common-id for Temp service) is not set");
183             return null;
184         }
185     }
186
187     public CancelResourceReserveOutput cancelPCEResource(String serviceName, ServiceNotificationTypes notifType) {
188         LOG.info("Calling cancel resource reserve computation.");
189         notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
190                 .setStatus(RpcStatusEx.Pending)
191                 .setStatusMessage("submitting Cancel resource reserve Request ...").build();
192         try {
193             notificationPublishService.putNotification(notification);
194         } catch (InterruptedException e) {
195             LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
196         }
197         FutureCallback<CancelResourceReserveOutput> pceCallback =
198                 new CancelResourceReserveOutputFutureCallback(notifType, serviceName);
199         CancelResourceReserveInput cancelResourceReserveInput = mappingCancelResourceReserve(serviceName, null);
200         ConfigurationResponseCommonBuilder configurationResponseCommon = new ConfigurationResponseCommonBuilder();
201         if (cancelResourceReserveInput != null) {
202             String requestId = cancelResourceReserveInput.getServiceHandlerHeader().getRequestId();
203             ListenableFuture<CancelResourceReserveOutput> pce =
204                     this.pathComputationService.cancelResourceReserve(cancelResourceReserveInput);
205             Futures.addCallback(pce, pceCallback, executor);
206             if (requestId != null) {
207                 configurationResponseCommon.setRequestId(requestId);
208             }
209             configurationResponseCommon.setAckFinalIndicator(ResponseCodes.FINAL_ACK_NO)
210                     .setResponseCode(ResponseCodes.RESPONSE_OK).setResponseMessage("PCE calculation in progress");
211             return new CancelResourceReserveOutputBuilder()
212                     .setConfigurationResponseCommon(configurationResponseCommon.build()).build();
213         } else {
214             configurationResponseCommon.setAckFinalIndicator(ResponseCodes.FINAL_ACK_YES)
215                     .setResponseCode(ResponseCodes.RESPONSE_FAILED).setResponseMessage("PCE failed !");
216             return new CancelResourceReserveOutputBuilder()
217                     .setConfigurationResponseCommon(configurationResponseCommon.build()).build();
218         }
219     }
220
221     private static PathComputationRequestOutput returnPCEFailed() {
222         ConfigurationResponseCommon configurationResponseCommon = new ConfigurationResponseCommonBuilder()
223                 .setAckFinalIndicator(ResponseCodes.FINAL_ACK_YES).setResponseCode(ResponseCodes.RESPONSE_FAILED)
224                 .setResponseMessage("PCE calculation failed").build();
225         ResponseParameters reponseParameters = new ResponseParametersBuilder().build();
226         return new PathComputationRequestOutputBuilder().setConfigurationResponseCommon(configurationResponseCommon)
227                 .setResponseParameters(reponseParameters).build();
228     }
229
230     private Boolean validateParams(String serviceName, SdncRequestHeader sdncRequestHeader) {
231         boolean result = true;
232         if (!checkString(serviceName)) {
233             result = false;
234             LOG.error("Service Name (common-id for Temp service) is not set");
235         } else if (sdncRequestHeader == null) {
236             LOG.error("Service sdncRequestHeader 'request-id' is not set");
237             result = false;
238         }
239         return result;
240     }
241
242     private static boolean checkString(String value) {
243         return ((value != null) && (value.compareTo("") != 0));
244     }
245
246     private final class CancelResourceReserveOutputFutureCallback
247             implements FutureCallback<CancelResourceReserveOutput> {
248         private final ServiceNotificationTypes notifType;
249         private final String serviceName;
250         String message = "";
251         ServiceRpcResultSh notification = null;
252
253         private CancelResourceReserveOutputFutureCallback(ServiceNotificationTypes notifType, String serviceName) {
254             this.notifType = notifType;
255             this.serviceName = serviceName;
256         }
257
258         @Override
259         public void onSuccess(CancelResourceReserveOutput response) {
260             if (response != null) {
261                 /**
262                  * If PCE reply is received before timer expiration with a positive result, a
263                  * service is created with admin and operational status 'down'.
264                  */
265                 message = "PCE replied to CRR Request !";
266                 LOG.info("PCE replied to CRR Request : {}", response);
267                 notification =
268                         new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
269                                 .setStatus(RpcStatusEx.Successful).setStatusMessage(message).build();
270                 try {
271                     notificationPublishService.putNotification(notification);
272                 } catch (InterruptedException e) {
273                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
274                 }
275             } else {
276                 message = "PCE failed ";
277                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName("")
278                         .setStatus(RpcStatusEx.Failed).setStatusMessage(message).build();
279                 try {
280                     notificationPublishService.putNotification(notification);
281                 } catch (InterruptedException e) {
282                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
283                 }
284             }
285         }
286
287         @Override
288         public void onFailure(Throwable arg0) {
289             LOG.error("Cancel resource failed !");
290             notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
291                     .setServiceName(serviceName).setStatus(RpcStatusEx.Failed)
292                     .setStatusMessage("CRR Request failed  : " + arg0.getMessage()).build();
293             try {
294                 notificationPublishService.putNotification(notification);
295             } catch (InterruptedException e) {
296                 LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
297             }
298         }
299     }
300
301     private final class PathComputationRequestOutputCallback implements FutureCallback<PathComputationRequestOutput> {
302         private final ServiceNotificationTypes notifType;
303         private final String serviceName;
304         String message = "";
305         ServiceRpcResultSh notification = null;
306
307         private PathComputationRequestOutputCallback(ServiceNotificationTypes notifType, String serviceName) {
308             this.notifType = notifType;
309             this.serviceName = serviceName;
310         }
311
312         @Override
313         public void onSuccess(PathComputationRequestOutput response) {
314             if (response != null) {
315                 /**
316                  * If PCE reply is received before timer expiration with a positive result, a
317                  * service is created with admin and operational status 'down'.
318                  */
319                 message = "PCE replied to PCR Request !";
320                 LOG.info("PCE replied to PCR Request : {}", response);
321                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
322                         .setServiceName(serviceName)
323                         .setStatus(RpcStatusEx.Successful).setStatusMessage(message).build();
324                 try {
325                     notificationPublishService.putNotification(notification);
326                 } catch (InterruptedException e) {
327                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
328                 }
329             } else {
330                 message = "PCE failed ";
331                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName("")
332                         .setStatus(RpcStatusEx.Failed).setStatusMessage(message).build();
333                 try {
334                     notificationPublishService.putNotification(notification);
335                 } catch (InterruptedException e) {
336                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
337                 }
338             }
339         }
340
341         @Override
342         public void onFailure(Throwable arg0) {
343             LOG.error("Path not calculated..");
344             notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
345                     .setServiceName(serviceName)
346                     .setStatus(RpcStatusEx.Failed).setStatusMessage("PCR Request failed  : " + arg0.getMessage())
347                     .build();
348             try {
349                 notificationPublishService.putNotification(notification);
350             } catch (InterruptedException e) {
351                 LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
352             }
353         }
354     }
355 }