Do not use RpcService in TPCE pce module
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / service / PathComputationServiceImpl.java
1 /*
2  * Copyright © 2017 AT&T, 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.pce.service;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import com.google.common.util.concurrent.ListeningExecutorService;
12 import com.google.common.util.concurrent.MoreExecutors;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import java.util.concurrent.Executors;
18 import java.util.stream.Collectors;
19 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
20 import org.opendaylight.transportpce.common.mapping.PortMapping;
21 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
22 import org.opendaylight.transportpce.pce.PceComplianceCheck;
23 import org.opendaylight.transportpce.pce.PceComplianceCheckResult;
24 import org.opendaylight.transportpce.pce.PceSendingPceRPCs;
25 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
26 import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
27 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.Response;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveInput;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveOutput;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.CancelResourceReserveOutputBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestInputBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestOutput;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRequestOutputBuilder;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestInput;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestOutput;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.PathComputationRerouteRequestOutputBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.ServicePathRpcResult;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.ServicePathRpcResultBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.GnpyResponse;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.GnpyResponseBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.gnpy.response.response.type.NoPathCaseBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.gnpy.gnpy.response.response.type.PathCaseBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceAEndBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.computation.request.input.ServiceZEndBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.PathPropertiesBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.path.properties.PathMetric;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.path.performance.path.properties.PathMetricBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.service.path.rpc.result.PathDescription;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220808.service.path.rpc.result.PathDescriptionBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.configuration.response.common.ConfigurationResponseCommonBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.AToZDirection;
53 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.ZToADirection;
54 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
55 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
56 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
57 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.handler.header.ServiceHandlerHeaderBuilder;
58 import org.osgi.service.component.annotations.Activate;
59 import org.osgi.service.component.annotations.Component;
60 import org.osgi.service.component.annotations.Reference;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 @Component(immediate = true)
65 public class PathComputationServiceImpl implements PathComputationService {
66
67     private static final Logger LOG = LoggerFactory.getLogger(PathComputationServiceImpl.class);
68     private final NotificationPublishService notificationPublishService;
69     private NetworkTransactionService networkTransactionService;
70     private final ListeningExecutorService executor;
71     private ServicePathRpcResult notification = null;
72     private final GnpyConsumer gnpyConsumer;
73     private PortMapping portMapping;
74
75     @Activate
76     public PathComputationServiceImpl(@Reference NetworkTransactionService networkTransactionService,
77             @Reference NotificationPublishService notificationPublishService,
78             @Reference GnpyConsumer gnpyConsumer,
79             @Reference PortMapping portMapping) {
80         this.notificationPublishService = notificationPublishService;
81         this.networkTransactionService = networkTransactionService;
82         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
83         this.gnpyConsumer = gnpyConsumer;
84         this.portMapping = portMapping;
85         LOG.info("PathComputationServiceImpl instantiated");
86     }
87
88     @SuppressFBWarnings(
89         value = "UPM_UNCALLED_PRIVATE_METHOD",
90         justification = "false positive, this method is used by public method cancelResourceReserve")
91     private void sendNotifications(
92             ServicePathNotificationTypes servicePathNotificationTypes,
93             String serviceName,
94             RpcStatusEx rpcStatusEx,
95             String message,
96             PathDescription pathDescription) {
97         ServicePathRpcResultBuilder servicePathRpcResultBuilder =
98             new ServicePathRpcResultBuilder()
99                 .setNotificationType(servicePathNotificationTypes)
100                 .setServiceName(serviceName)
101                 .setStatus(rpcStatusEx)
102                 .setStatusMessage(message);
103         if (pathDescription != null) {
104             servicePathRpcResultBuilder.setPathDescription(pathDescription);
105         }
106         this.notification = servicePathRpcResultBuilder.build();
107         try {
108             notificationPublishService.putNotification(this.notification);
109         } catch (InterruptedException e) {
110             LOG.info("notification offer rejected: ", e);
111         }
112     }
113
114     @Override
115     public ListenableFuture<CancelResourceReserveOutput> cancelResourceReserve(CancelResourceReserveInput input) {
116         LOG.info("cancelResourceReserve");
117         return executor.submit(new Callable<CancelResourceReserveOutput>() {
118
119             @Override
120             public CancelResourceReserveOutput call() throws Exception {
121                 sendNotifications(
122                         ServicePathNotificationTypes.CancelResourceReserve,
123                         input.getServiceName(),
124                         RpcStatusEx.Pending,
125                         "Service compliant, submitting cancelResourceReserve Request ...",
126                         null);
127                 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(gnpyConsumer);
128                 sendingPCE.cancelResourceReserve();
129                 LOG.info("in PathComputationServiceImpl : {}",
130                         Boolean.TRUE.equals(sendingPCE.getSuccess())
131                             ? "ResourceReserve cancelled !"
132                             : "Cancelling ResourceReserve failed !");
133                 sendNotifications(
134                         ServicePathNotificationTypes.CancelResourceReserve,
135                         input.getServiceName(),
136                         RpcStatusEx.Successful,
137                         "cancel Resource Reserve successful!",
138                         null);
139                 return new CancelResourceReserveOutputBuilder()
140                     .setConfigurationResponseCommon(
141                         new ConfigurationResponseCommonBuilder()
142                             .setAckFinalIndicator("Yes")
143                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
144                             .setResponseCode("200")
145                             .setResponseMessage("")
146                             .build())
147                     .build();
148             }
149         });
150     }
151
152     @Override
153     public ListenableFuture<PathComputationRequestOutput> pathComputationRequest(PathComputationRequestInput input) {
154         LOG.debug("input parameters are : input = {}", input.toString());
155         return executor.submit(new Callable<PathComputationRequestOutput>() {
156
157             @Override
158             public PathComputationRequestOutput call() throws Exception {
159                 PathComputationRequestOutputBuilder output = new PathComputationRequestOutputBuilder();
160                 ConfigurationResponseCommonBuilder configurationResponseCommon =
161                         new ConfigurationResponseCommonBuilder();
162                 PceComplianceCheckResult check = PceComplianceCheck.check(input);
163                 if (!check.hasPassed()) {
164                     LOG.error("Path not calculated, service not compliant : {}", check.getMessage());
165                     sendNotifications(
166                         ServicePathNotificationTypes.PathComputationRequest,
167                         input.getServiceName(),
168                         RpcStatusEx.Failed,
169                         "Path not calculated, service not compliant",
170                         null);
171                     configurationResponseCommon
172                             .setAckFinalIndicator("Yes")
173                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
174                             .setResponseCode("Path not calculated")
175                             .setResponseMessage(check.getMessage());
176                     return output
177                         .setConfigurationResponseCommon(configurationResponseCommon.build())
178                         .setResponseParameters(null)
179                         .build();
180                 }
181                 sendNotifications(
182                     ServicePathNotificationTypes.PathComputationRequest,
183                     input.getServiceName(),
184                     RpcStatusEx.Pending,
185                     "Service compliant, submitting pathComputation Request ...",
186                     null);
187                 PceSendingPceRPCs sendingPCE =
188                     new PceSendingPceRPCs(input, networkTransactionService, gnpyConsumer, portMapping);
189                 sendingPCE.pathComputation();
190                 String message = sendingPCE.getMessage();
191                 String responseCode = sendingPCE.getResponseCode();
192                 LOG.info("PCE response: {} {}", message, responseCode);
193
194                 //add the GNPy result
195                 GnpyResult gnpyAtoZ = sendingPCE.getGnpyAtoZ();
196                 GnpyResult gnpyZtoA = sendingPCE.getGnpyZtoA();
197                 List<GnpyResponse> listResponse = new ArrayList<>();
198                 if (gnpyAtoZ != null) {
199                     GnpyResponse respAtoZ = generateGnpyResponse(gnpyAtoZ.getResponse(),"A-to-Z");
200                     listResponse.add(respAtoZ);
201                 }
202                 if (gnpyZtoA != null) {
203                     GnpyResponse respZtoA = generateGnpyResponse(gnpyZtoA.getResponse(),"Z-to-A");
204                     listResponse.add(respZtoA);
205                 }
206                 output
207                     .setGnpyResponse(
208                         listResponse.stream()
209                             .collect(Collectors.toMap(GnpyResponse::key, gnpyResponse -> gnpyResponse)));
210
211                 PathDescriptionBuilder path = sendingPCE.getPathDescription();
212                 if (Boolean.FALSE.equals(sendingPCE.getSuccess()) || (path == null)) {
213                     sendNotifications(
214                         ServicePathNotificationTypes.PathComputationRequest,
215                         input.getServiceName(),
216                         RpcStatusEx.Failed,
217                         "Path not calculated",
218                         null);
219                     return output
220                         .setConfigurationResponseCommon(
221                             configurationResponseCommon
222                                 .setAckFinalIndicator("Yes")
223                                 .setRequestId(input.getServiceHandlerHeader().getRequestId())
224                                 .setResponseCode(responseCode)
225                                 .setResponseMessage(message)
226                                 .build())
227                         .build();
228                 }
229                 // Path calculator returned Success
230                 PathDescription pathDescription =
231                     new PathDescriptionBuilder()
232                         .setAToZDirection(path.getAToZDirection())
233                         .setZToADirection(path.getZToADirection())
234                         .build();
235                 sendNotifications(
236                     ServicePathNotificationTypes.PathComputationRequest,
237                     input.getServiceName(),
238                     RpcStatusEx.Successful,
239                     message,
240                     pathDescription);
241                 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
242                         .response.parameters.sp.response.parameters.PathDescription pathDescription1 =
243                     new org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
244                             .response.parameters.sp.response.parameters.PathDescriptionBuilder()
245                         .setAToZDirection(path.getAToZDirection())
246                         .setZToADirection(path.getZToADirection())
247                         .build();
248                 output
249                     .setConfigurationResponseCommon(
250                         configurationResponseCommon
251                             .setAckFinalIndicator("Yes")
252                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
253                             .setResponseCode(responseCode)
254                             .setResponseMessage(message)
255                             .build())
256                     .setResponseParameters(
257                         new ResponseParametersBuilder().setPathDescription(pathDescription1).build());
258                 //debug prints
259                 AToZDirection atoz = pathDescription.getAToZDirection();
260                 if ((atoz != null) && (atoz.getAToZ() != null)) {
261                     LOG.debug("Impl AtoZ Notification: [{}] elements in description", atoz.getAToZ().size());
262                     for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501
263                             .path.description.atoz.direction.AToZKey key : atoz.getAToZ().keySet()) {
264                         LOG.debug("Impl AtoZ Notification: [{}] {}", key, atoz.getAToZ().get(key));
265                     }
266                 }
267                 ZToADirection ztoa = pathDescription.getZToADirection();
268                 if ((ztoa != null) && (ztoa.getZToA() != null)) {
269                     LOG.debug("Impl ZtoA Notification: [{}] elements in description", ztoa.getZToA().size());
270                     for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501
271                             .path.description.ztoa.direction.ZToAKey key : ztoa.getZToA().keySet()) {
272                         LOG.debug("Impl ZtoA Notification: [{}] {}", key, ztoa.getZToA().get(key));
273                     }
274                 }
275                 return output.build();
276             }
277         });
278     }
279
280     @Override
281     public ListenableFuture<PathComputationRerouteRequestOutput> pathComputationRerouteRequest(
282             PathComputationRerouteRequestInput input) {
283         return executor.submit(() -> {
284             PathComputationRerouteRequestOutputBuilder output = new PathComputationRerouteRequestOutputBuilder();
285             ConfigurationResponseCommonBuilder configurationResponseCommon = new ConfigurationResponseCommonBuilder()
286                     .setRequestId("none");
287             PceComplianceCheckResult check = PceComplianceCheck.check(input);
288             if (!check.hasPassed()) {
289                 LOG.error("Path not calculated, path computation reroute request not compliant : {}",
290                         check.getMessage());
291                 configurationResponseCommon
292                         .setAckFinalIndicator("Yes")
293                         .setResponseCode("Path not calculated")
294                         .setResponseMessage(check.getMessage());
295                 return output
296                         .setConfigurationResponseCommon(configurationResponseCommon.build())
297                         .build();
298             }
299             PathComputationRequestInput pathComputationInput = new PathComputationRequestInputBuilder()
300                     .setServiceName("no_name")
301                     .setServiceHandlerHeader(new ServiceHandlerHeaderBuilder().setRequestId("none").build())
302                     .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
303                     .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
304                     .setHardConstraints(input.getHardConstraints())
305                     .setPceRoutingMetric(input.getPceRoutingMetric())
306                     .setResourceReserve(false)
307                     .setSoftConstraints(input.getSoftConstraints())
308                     .setRoutingMetric(input.getRoutingMetric())
309                     .build();
310             PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(pathComputationInput, networkTransactionService,
311                     gnpyConsumer, portMapping, input.getEndpoints());
312             sendingPCE.pathComputation();
313             String message = sendingPCE.getMessage();
314             String responseCode = sendingPCE.getResponseCode();
315             LOG.info("PCE response: {} {}", message, responseCode);
316             return output.setConfigurationResponseCommon(
317                     configurationResponseCommon
318                             .setAckFinalIndicator("Yes")
319                             .setResponseCode(responseCode)
320                             .setResponseMessage(message)
321                             .build())
322                     .build();
323         });
324     }
325
326     public GnpyResponse generateGnpyResponse(Response responseGnpy, String pathDir) {
327         if (responseGnpy == null) {
328             return new GnpyResponseBuilder()
329                 .setPathDir(pathDir)
330                 .setResponseType(null)
331                 .setFeasibility(true)
332                 .build();
333         }
334         if (responseGnpy.getResponseType()
335                 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase) {
336             LOG.info("GNPy : path is not feasible");
337             org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase
338                     noPathGnpy =
339                 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase)
340                     responseGnpy.getResponseType();
341             return new GnpyResponseBuilder()
342                 .setPathDir(pathDir)
343                 .setResponseType(
344                     new NoPathCaseBuilder()
345                         .setNoPath(noPathGnpy.getNoPath())
346                         .build())
347                 .setFeasibility(false)
348                 .build();
349         }
350         if (responseGnpy.getResponseType()
351                 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase) {
352             LOG.info("GNPy : path is feasible");
353             org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase
354                     pathCase =
355                 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase)
356                     responseGnpy.getResponseType();
357             List<org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric>
358                     pathMetricList =
359                 new ArrayList<>(pathCase.getPathProperties().getPathMetric().values());
360             List<PathMetric> gnpyPathMetricList = new ArrayList<>();
361             for (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric
362                     pathMetricGnpy : pathMetricList) {
363                 gnpyPathMetricList.add(
364                     new PathMetricBuilder()
365                         .setMetricType(pathMetricGnpy.getMetricType())
366                         .setAccumulativeValue(pathMetricGnpy.getAccumulativeValue())
367                         .build());
368             }
369             return new GnpyResponseBuilder()
370                 .setPathDir(pathDir)
371                 .setResponseType(
372                     new PathCaseBuilder()
373                         .setPathProperties(
374                             new PathPropertiesBuilder()
375                                 .setPathMetric(gnpyPathMetricList.stream()
376                                     .collect(Collectors.toMap(PathMetric::key, pathMetric -> pathMetric)))
377                                 .build())
378                         .build())
379                 .setFeasibility(true)
380                 .build();
381         }
382         return new GnpyResponseBuilder()
383             .setPathDir(pathDir)
384             .setResponseType(null)
385             .setFeasibility(true)
386             .build();
387     }
388
389 }