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