Bump upstream dependencies to Ca
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
1 /*
2  * Copyright © 2017 AT&T 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.renderer.provisiondevice;
9
10 import com.google.common.util.concurrent.Futures;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import com.google.common.util.concurrent.ListeningExecutorService;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Optional;
19 import java.util.Set;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import java.util.stream.Collectors;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.binding.api.RpcService;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.ResponseCodes;
30 import org.opendaylight.transportpce.common.StringConstants;
31 import org.opendaylight.transportpce.common.Timeouts;
32 import org.opendaylight.transportpce.common.mapping.PortMapping;
33 import org.opendaylight.transportpce.common.service.ServiceTypes;
34 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
35 import org.opendaylight.transportpce.renderer.ServicePathInputData;
36 import org.opendaylight.transportpce.renderer.provisiondevice.notification.Notification;
37 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.NetworkDeviceRenderingRollbackTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
42 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
43 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerTurnDownTask;
44 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
45 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
46 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackResultMessage;
47 import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History;
48 import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.TransactionHistory;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPm;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetup;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndown;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
62 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
63 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
64 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
65 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
66 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
67 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
68 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
69 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
70 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.PathDescription;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
77 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.PmGranularity;
78 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
79 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.olm.get.pm.input.ResourceIdentifierBuilder;
80 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.common.Uint32;
83 import org.osgi.service.component.annotations.Activate;
84 import org.osgi.service.component.annotations.Component;
85 import org.osgi.service.component.annotations.Reference;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89
90 @Component(immediate = true)
91 public class RendererServiceOperationsImpl implements RendererServiceOperations {
92
93     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
94     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
95             "Device rendering was not successful! Rendering will be rolled back.";
96     private static final String OLM_ROLL_BACK_MSG =
97             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
98     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
99     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
100     private static final String ATOZPATH = "A-to-Z";
101     private static final String ZTOAPATH = "Z-to-A";
102     private static final String OPERATION_FAILED = "Operation Failed";
103     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
104     private static final int NUMBER_OF_THREADS = 4;
105
106     private final DeviceRendererService deviceRenderer;
107     private final OtnDeviceRendererService otnDeviceRenderer;
108     private final DataBroker dataBroker;
109     private final Notification notification;
110     private final PortMapping portMapping;
111     private final RpcService rpcService;
112     private ListeningExecutorService executor;
113
114     @Activate
115     public RendererServiceOperationsImpl(@Reference DeviceRendererService deviceRenderer,
116             @Reference OtnDeviceRendererService otnDeviceRenderer,
117             @Reference DataBroker dataBroker,
118             @Reference Notification notification,
119             @Reference PortMapping portMapping,
120             @Reference RpcService rpcService) {
121         this.deviceRenderer = deviceRenderer;
122         this.otnDeviceRenderer = otnDeviceRenderer;
123         this.dataBroker = dataBroker;
124         this.notification = notification;
125         this.portMapping = portMapping;
126         this.rpcService = rpcService;
127         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
128         LOG.debug("RendererServiceOperationsImpl instantiated");
129     }
130
131     @Override
132     public ListenableFuture<ServiceImplementationRequestOutput>
133             serviceImplementation(ServiceImplementationRequestInput input, boolean isTempService) {
134         LOG.info("Calling service impl request {}", input.getServiceName());
135         LOG.debug("Check if it is temp-service {}", isTempService);
136         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
137
138             @Override
139             public ServiceImplementationRequestOutput call() throws Exception {
140                 sendNotifications(
141                     ServicePathNotificationTypes.ServiceImplementationRequest,
142                     input.getServiceName(),
143                     RpcStatusEx.Pending,
144                     "Service compliant, submitting service implementation Request ...");
145                 Uint32 serviceRate = getServiceRate(input);
146                 LOG.info("Using {}G rate", serviceRate);
147                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221
148                         .network.Nodes mappingNode =
149                     portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
150                         ? portMapping.getNode(input.getServiceAEnd().getNodeId())
151                         : null;
152                 String serviceType = ServiceTypes.getServiceType(
153                     input.getServiceAEnd().getServiceFormat().getName(),
154                     serviceRate,
155                     mappingNode != null
156                         && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
157                             && input.getServiceAEnd().getTxDirection() != null
158                             && input.getServiceAEnd().getTxDirection().getPort() != null
159                             && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
160                         ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
161                                 input.getServiceAEnd().getTxDirection().getPort().getPortName())
162                         : null);
163                 //TODO a Map might be more indicated here
164                 switch (serviceType) {
165                     case StringConstants.SERVICE_TYPE_100GE_T:
166                     case StringConstants.SERVICE_TYPE_400GE:
167                     case StringConstants.SERVICE_TYPE_OTU4:
168                     case StringConstants.SERVICE_TYPE_OTUC2:
169                     case StringConstants.SERVICE_TYPE_OTUC3:
170                     case StringConstants.SERVICE_TYPE_OTUC4:
171                         LOG.debug("Check temp service {}", isTempService);
172                         if (!manageServicePathCreation(input, serviceType, isTempService)) {
173                             return ModelMappingUtils
174                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
175                         }
176                         break;
177                     case StringConstants.SERVICE_TYPE_1GE:
178                     case StringConstants.SERVICE_TYPE_10GE:
179                     case StringConstants.SERVICE_TYPE_100GE_M:
180                     case StringConstants.SERVICE_TYPE_100GE_S:
181                     case StringConstants.SERVICE_TYPE_ODU4:
182                     case StringConstants.SERVICE_TYPE_ODUC2:
183                     case StringConstants.SERVICE_TYPE_ODUC3:
184                     case StringConstants.SERVICE_TYPE_ODUC4:
185                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
186                             return ModelMappingUtils
187                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
188                         }
189                         break;
190                     default:
191                         LOG.error("unsupported service-type");
192                         return ModelMappingUtils
193                             .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
194                 }
195                 return ModelMappingUtils
196                     .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
197             }
198         });
199     }
200
201     @Override
202     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
203         String serviceName = input.getServiceName();
204         LOG.info("Calling service delete request {}", serviceName);
205         return executor.submit(new Callable<ServiceDeleteOutput>() {
206
207             @Override
208             public ServiceDeleteOutput call() throws Exception {
209                 sendNotifications(
210                     ServicePathNotificationTypes.ServiceDelete,
211                     serviceName,
212                     RpcStatusEx.Pending,
213                     "Service compliant, submitting service delete Request ...");
214                 // Obtain path description
215                 Optional<
216                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
217                         .service.path.PathDescription> pathDescriptionOpt =
218                     getPathDescriptionFromDatastore(serviceName);
219                 if (pathDescriptionOpt.isEmpty()) {
220                     LOG.error("Unable to get path description for service {}!", serviceName);
221                     sendNotifications(
222                         ServicePathNotificationTypes.ServiceDelete,
223                         serviceName,
224                         RpcStatusEx.Failed,
225                         "Unable to get path description for service");
226                     return ModelMappingUtils
227                         .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
228                 }
229                 PathDescription pathDescription = pathDescriptionOpt.orElseThrow();
230                 String serviceType =
231                     ServiceTypes.getServiceType(
232                         service.getServiceAEnd().getServiceFormat().getName(),
233                         service.getServiceAEnd().getServiceRate(),
234                         service.getServiceAEnd().getTxDirection() == null
235                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
236                                     .getPort() == null
237                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
238                                     .getPort().getPortName() == null
239                             ? null
240                             : portMapping.getMapping(
241                                     service.getServiceAEnd().getNodeId().getValue(),
242                                     service.getServiceAEnd().getTxDirection().values().stream().findFirst()
243                                         .orElseThrow().getPort().getPortName()));
244                 switch (serviceType) {
245                     case StringConstants.SERVICE_TYPE_100GE_T:
246                     case StringConstants.SERVICE_TYPE_400GE:
247                     case StringConstants.SERVICE_TYPE_OTU4:
248                     case StringConstants.SERVICE_TYPE_OTUC2:
249                     case StringConstants.SERVICE_TYPE_OTUC3:
250                     case StringConstants.SERVICE_TYPE_OTUC4:
251                         if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
252                             return ModelMappingUtils
253                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
254                         }
255                         break;
256                     case StringConstants.SERVICE_TYPE_1GE:
257                     case StringConstants.SERVICE_TYPE_10GE:
258                     case StringConstants.SERVICE_TYPE_100GE_M:
259                     case StringConstants.SERVICE_TYPE_100GE_S:
260                     case StringConstants.SERVICE_TYPE_ODU4:
261                     case StringConstants.SERVICE_TYPE_ODUC2:
262                     case StringConstants.SERVICE_TYPE_ODUC3:
263                     case StringConstants.SERVICE_TYPE_ODUC4:
264                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
265                             return ModelMappingUtils
266                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
267                         }
268                         break;
269                     default:
270                         LOG.error("unsupported service-type");
271                         return ModelMappingUtils
272                             .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
273                 }
274                 return ModelMappingUtils
275                     .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
276             }
277         });
278     }
279
280     @SuppressFBWarnings(
281         value = "UPM_UNCALLED_PRIVATE_METHOD",
282         justification = "call in call() method")
283     private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
284         if (input.getServiceAEnd() == null) {
285             LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
286             return Uint32.ZERO;
287         }
288         if (input.getServiceAEnd().getServiceRate() != null) {
289             return input.getServiceAEnd().getServiceRate();
290         }
291         LOG.warn("Input should have rate if you are using 200 or 300G");
292         // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
293         Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
294                 ServiceFormat.OTU, Map.of(
295                     "OTUCn", Uint32.valueOf(400),
296                     "OTU4", Uint32.valueOf(100),
297                     "OTU2", Uint32.valueOf(10),
298                     "OTU2e", Uint32.valueOf(10)),
299                 ServiceFormat.ODU, Map.of(
300                     "ODUCn",Uint32.valueOf(400),
301                     "ODU4", Uint32.valueOf(100),
302                     "ODU2", Uint32.valueOf(10),
303                     "ODU2e", Uint32.valueOf(10),
304                     "ODU0", Uint32.valueOf(1)));
305         if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
306             LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
307                 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
308             return Uint32.ZERO;
309         }
310         String serviceName =
311             ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
312                 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
313                 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
314         if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
315             LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
316                 input.getServiceName(), serviceName);
317             return Uint32.ZERO;
318         }
319         return formatRateMap
320             .get(input.getServiceAEnd().getServiceFormat())
321             .get(serviceName);
322     }
323
324     @SuppressFBWarnings(
325             value = "UPM_UNCALLED_PRIVATE_METHOD",
326             justification = "call in call() method")
327     private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
328             .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
329         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
330                 .service.path.PathDescription> pathDescriptionIID =
331             InstanceIdentifier.create(ServicePathList.class)
332                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
333                 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
334                     .service.path.PathDescription.class);
335         try {
336             LOG.debug("Getting path description for service {}", serviceName);
337             return this.dataBroker.newReadOnlyTransaction()
338                     .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
339                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
340         } catch (InterruptedException | ExecutionException | TimeoutException e) {
341             LOG.warn("Exception while getting path description from datastore {} for service {}!",
342                     pathDescriptionIID, serviceName, e);
343             return Optional.empty();
344         }
345     }
346
347     @SuppressFBWarnings(
348             value = "UPM_UNCALLED_PRIVATE_METHOD",
349             justification = "call in call() method")
350     private List<DeviceRenderingResult> deviceRendering(
351             RollbackProcessor rollbackProcessor,
352             ServicePathInputData servicePathDataAtoZ,
353             ServicePathInputData servicePathDataZtoA) {
354
355         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
356         //     Do notifications & LOG.info deserve this ?
357         LOG.info(RENDERING_DEVICES_A_Z_MSG);
358         sendNotifications(
359             ServicePathNotificationTypes.ServiceImplementationRequest,
360             servicePathDataAtoZ.getServicePathInput().getServiceName(),
361             RpcStatusEx.Pending,
362             RENDERING_DEVICES_A_Z_MSG);
363
364         History transactionHistory = new TransactionHistory();
365         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
366             this.executor.submit(
367                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z,
368                         transactionHistory));
369
370         LOG.info(RENDERING_DEVICES_Z_A_MSG);
371         sendNotifications(
372             ServicePathNotificationTypes.ServiceImplementationRequest,
373             servicePathDataZtoA.getServicePathInput().getServiceName(),
374             RpcStatusEx.Pending,
375             RENDERING_DEVICES_Z_A_MSG);
376         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
377             this.executor.submit(
378                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A,
379                         transactionHistory));
380
381         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
382             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
383
384         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
385         try {
386             LOG.info("Waiting for A-Z and Z-A device renderers ...");
387             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
388         } catch (InterruptedException | ExecutionException | TimeoutException e) {
389             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
390             sendNotifications(
391                 ServicePathNotificationTypes.ServiceImplementationRequest,
392                 servicePathDataAtoZ.getServicePathInput().getServiceName(),
393                 RpcStatusEx.Pending,
394                 DEVICE_RENDERING_ROLL_BACK_MSG);
395             //FIXME we can't do rollback here, because we don't have rendering results.
396             return renderingResults;
397         }
398
399         rollbackProcessor.addTask(
400             new NetworkDeviceRenderingRollbackTask(
401                 "RollbackTransactionHistoryTask",
402                 transactionHistory,
403                 ! (renderingResults.get(0).isSuccess() && renderingResults.get(1).isSuccess()),
404                 deviceRenderer,
405                 new RollbackResultMessage()
406             )
407         );
408
409         return renderingResults;
410     }
411
412     @SuppressFBWarnings(
413         value = "UPM_UNCALLED_PRIVATE_METHOD",
414         justification = "call in call() method")
415     private List<OtnDeviceRenderingResult> otnDeviceRendering(
416             RollbackProcessor rollbackProcessor,
417             OtnServicePathInput otnServicePathAtoZ,
418             OtnServicePathInput otnServicePathZtoA,
419             String serviceType) {
420
421         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
422         //     Do notifications & LOG.info deserve this ?
423         LOG.info(RENDERING_DEVICES_A_Z_MSG);
424         sendNotifications(
425             ServicePathNotificationTypes.ServiceImplementationRequest,
426             otnServicePathAtoZ.getServiceName(),
427             RpcStatusEx.Pending,
428             RENDERING_DEVICES_A_Z_MSG);
429         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
430             this.executor.submit(
431                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
432
433         LOG.info(RENDERING_DEVICES_Z_A_MSG);
434         sendNotifications(
435             ServicePathNotificationTypes.ServiceImplementationRequest,
436             otnServicePathZtoA.getServiceName(),
437             RpcStatusEx.Pending,
438             RENDERING_DEVICES_Z_A_MSG);
439         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
440             this.executor.submit(
441                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
442
443         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
444             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
445         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
446         try {
447             LOG.info("Waiting for A-Z and Z-A device renderers ...");
448             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
449         } catch (InterruptedException | ExecutionException | TimeoutException e) {
450             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
451             sendNotifications(
452                 ServicePathNotificationTypes.ServiceImplementationRequest,
453                 otnServicePathAtoZ.getServiceName(),
454                 RpcStatusEx.Pending,
455                 DEVICE_RENDERING_ROLL_BACK_MSG);
456             //FIXME we can't do rollback here, because we don't have rendering results.
457             return otnRenderingResults;
458         }
459         for (int i = 0; i < otnRenderingResults.size(); i++) {
460             rollbackProcessor.addTask(
461                 new DeviceRenderingRollbackTask(
462                     "DeviceTask n° " + i + 1,
463                     ! otnRenderingResults.get(i).isSuccess(),
464                     otnRenderingResults.get(i).getRenderedNodeInterfaces(),
465                     this.deviceRenderer));
466         }
467         return otnRenderingResults;
468     }
469
470     @SuppressFBWarnings(
471             value = "UPM_UNCALLED_PRIVATE_METHOD",
472             justification = "call in call() method")
473     private void olmPowerSetup(
474             RollbackProcessor rollbackProcessor,
475             ServicePowerSetupInput powerSetupInputAtoZ,
476             ServicePowerSetupInput powerSetupInputZtoA, boolean isTempService) {
477
478         //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
479         //     Do notifications & LOG.info deserve this ?
480         //TODO use constants for LOG.info & notifications common messages
481         // if the service create is a temp-service, OLM will be skipped
482         if (isTempService) {
483             LOG.info("For temp-service create OLM is not computed and skipped");
484             return;
485         }
486         LOG.info("Olm power setup A-Z");
487         sendNotifications(
488                 ServicePathNotificationTypes.ServiceImplementationRequest,
489                 powerSetupInputAtoZ.getServiceName(),
490                 RpcStatusEx.Pending,
491                 "Olm power setup A-Z");
492         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
493                 this.executor.submit(
494                     new OlmPowerSetupTask(rpcService.getRpc(ServicePowerSetup.class), powerSetupInputAtoZ));
495
496         LOG.info("OLM power setup Z-A");
497         sendNotifications(
498                 ServicePathNotificationTypes.ServiceImplementationRequest,
499                 powerSetupInputAtoZ.getServiceName(),
500                 RpcStatusEx.Pending,
501                 "Olm power setup Z-A");
502         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
503                 this.executor.submit(
504                     new OlmPowerSetupTask(rpcService.getRpc(ServicePowerSetup.class), powerSetupInputZtoA));
505         ListenableFuture<List<OLMRenderingResult>> olmFutures =
506                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
507
508         List<OLMRenderingResult> olmResults;
509         try {
510             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
511             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
512         } catch (InterruptedException | ExecutionException | TimeoutException e) {
513             LOG.warn(OLM_ROLL_BACK_MSG, e);
514             sendNotifications(
515                     ServicePathNotificationTypes.ServiceImplementationRequest,
516                     powerSetupInputAtoZ.getServiceName(),
517                     RpcStatusEx.Pending,
518                     OLM_ROLL_BACK_MSG);
519             rollbackProcessor.addTask(
520                     new OlmPowerSetupRollbackTask("AtoZOLMTask", true, rpcService.getRpc(ServicePowerTurndown.class),
521                         powerSetupInputAtoZ));
522             rollbackProcessor.addTask(
523                     new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, rpcService.getRpc(ServicePowerTurndown.class),
524                         powerSetupInputZtoA));
525             return;
526         }
527         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask(
528                 "AtoZOLMTask", !olmResults.get(0).isSuccess(), rpcService.getRpc(ServicePowerTurndown.class),
529                 powerSetupInputAtoZ));
530         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask(
531                 "ZtoAOLMTask", !olmResults.get(1).isSuccess(), rpcService.getRpc(ServicePowerTurndown.class),
532                 powerSetupInputZtoA));
533     }
534
535     @SuppressFBWarnings(
536             value = "UPM_UNCALLED_PRIVATE_METHOD",
537             justification = "call in call() method")
538     private boolean isServiceActivated(String nodeId, String tpId) {
539         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
540         for (int i = 0; i < 3; i++) {
541             List<Measurements> measurements = getMeasurements(nodeId, tpId);
542             if (measurements == null) {
543                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
544                 return true;
545             }
546             if (verifyPreFecBer(measurements)) {
547                 return true;
548             }
549             try {
550                 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
551             } catch (InterruptedException ex) {
552                 Thread.currentThread().interrupt();
553             }
554         }
555         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
556         return false;
557     }
558
559     private List<Measurements> getMeasurements(String nodeId, String tp) {
560         try {
561             GetPmOutput getPmOutput = rpcService.getRpc(GetPm.class).invoke(
562                         new GetPmInputBuilder()
563                             .setNodeId(nodeId)
564                             .setGranularity(PmGranularity._15min)
565                             .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
566                             .setResourceType(ResourceTypeEnum.Interface)
567                             .build())
568                     .get()
569                     .getResult();
570             if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
571                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
572             } else {
573                 LOG.info("successfully finished calling OLM's get PM");
574                 return getPmOutput.getMeasurements();
575                 // may return null
576             }
577
578         } catch (ExecutionException | InterruptedException e) {
579             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
580         }
581         return null;
582     }
583
584     private boolean verifyPreFecBer(List<Measurements> measurements) {
585         double preFecCorrectedErrors = Double.MIN_VALUE;
586         double fecUncorrectableBlocks = Double.MIN_VALUE;
587
588         for (Measurements measurement : measurements) {
589             switch (measurement.getPmparameterName()) {
590                 case "preFECCorrectedErrors":
591                     preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
592                     break;
593                 case "FECUncorrectableBlocks":
594                     fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
595                     break;
596                 default:
597                     break;
598             }
599         }
600
601         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
602                 preFecCorrectedErrors, fecUncorrectableBlocks);
603
604         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
605             LOG.error("Data has uncorrectable errors, BER test failed");
606             return false;
607         }
608
609         double numOfBitsPerSecond = 112000000000d;
610         double threshold = 0.00002d;
611         double result = preFecCorrectedErrors / numOfBitsPerSecond;
612         LOG.info("PreFEC value is {}", Double.toString(result));
613         return result <= threshold;
614     }
615
616     @SuppressFBWarnings(
617         value = "UPM_UNCALLED_PRIVATE_METHOD",
618         justification = "call in call() method")
619     private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
620                                               boolean isTempService) {
621         ServicePathInputData servicePathInputDataAtoZ =
622             ModelMappingUtils
623                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
624         ServicePathInputData servicePathInputDataZtoA =
625             ModelMappingUtils
626                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
627         // Rollback should be same for all conditions, so creating a new one
628         RollbackProcessor rollbackProcessor = new RollbackProcessor();
629         List<DeviceRenderingResult> renderingResults =
630             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
631         if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
632             sendNotifications(
633                 ServicePathNotificationTypes.ServiceImplementationRequest,
634                 input.getServiceName(),
635                 RpcStatusEx.Failed,
636                 DEVICE_RENDERING_ROLL_BACK_MSG);
637             return false;
638         }
639         olmPowerSetup(
640             rollbackProcessor,
641             //olmPowerSetupInputAtoZ,
642             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
643             //olmPowerSetupInputZtoA
644             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input), isTempService);
645         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
646             sendNotifications(
647                 ServicePathNotificationTypes.ServiceImplementationRequest,
648                 input.getServiceName(),
649                 RpcStatusEx.Failed,
650                 OLM_ROLL_BACK_MSG);
651             return false;
652         }
653         // run service activation test twice - once on source node and once on
654         // destination node
655         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
656         if ((nodes == null) || (nodes.isEmpty())) {
657             return false;
658         }
659
660         Nodes sourceNode = nodes.get(0);
661         Nodes destNode = nodes.get(nodes.size() - 1);
662         String srcNetworkTp =
663             sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
664                 ? sourceNode.getDestTp()
665                 : sourceNode.getSrcTp();
666         String dstNetowrkTp =
667             destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
668                 ? destNode.getDestTp()
669                 : destNode.getSrcTp();
670
671         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
672                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
673             rollbackProcessor.rollbackAll();
674             sendNotifications(
675                 ServicePathNotificationTypes.ServiceImplementationRequest,
676                 input.getServiceName(),
677                 RpcStatusEx.Failed,
678                 "Service activation test failed.");
679             return false;
680         }
681         sendNotificationsWithPathDescription(
682             ServicePathNotificationTypes.ServiceImplementationRequest,
683             input.getServiceName(),
684             RpcStatusEx.Successful,
685             OPERATION_SUCCESSFUL,
686             input.getPathDescription(),
687             createLinkForNotif(
688                 renderingResults.stream()
689                     .flatMap(rr -> rr.getOtnLinkTps().stream())
690                     .collect(Collectors.toList())),
691             null,
692             serviceType);
693         return true;
694     }
695
696     @SuppressFBWarnings(
697         value = "UPM_UNCALLED_PRIVATE_METHOD",
698         justification = "call in call() method")
699     private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
700             throws InterruptedException {
701         ServicePathInputData servicePathInputDataAtoZ =
702             ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
703         ServicePathInputData servicePathInputDataZtoA =
704             ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
705
706         ListenableFuture<OLMRenderingResult> olmPowerTurnDownFutureAtoZ = this.executor.submit(
707                 new OlmPowerTurnDownTask(serviceName, ATOZPATH, servicePathInputDataAtoZ, notification, rpcService));
708
709         ListenableFuture<OLMRenderingResult> olmPowerTurnDownFutureZtoA = this.executor.submit(
710                 new OlmPowerTurnDownTask(serviceName, ZTOAPATH, servicePathInputDataZtoA, notification, rpcService));
711
712         ListenableFuture<List<OLMRenderingResult>> olmPowerTurnDownFutures =
713             Futures.allAsList(olmPowerTurnDownFutureAtoZ, olmPowerTurnDownFutureZtoA);
714
715         List<OLMRenderingResult> olmRenderingResults;
716         // OLM turn down power
717         try {
718             LOG.info("Waiting for A-Z and Z-A OLM power turn down ...");
719             olmRenderingResults = olmPowerTurnDownFutures.get(
720                 Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS
721             );
722         } catch (InterruptedException | ExecutionException | TimeoutException e) {
723             LOG.error("Error while turning down power!", e);
724             return false;
725         }
726         if (!olmRenderingResults.get(0).isSuccess() || !olmRenderingResults.get(1).isSuccess()) {
727             LOG.error("Error while turning down power!");
728             return false;
729         }
730         LOG.info("OLM power successfully turned down!");
731         // delete service path with renderer
732         LOG.info("Deleting service path via renderer");
733         sendNotifications(
734             ServicePathNotificationTypes.ServiceDelete,
735             serviceName,
736             RpcStatusEx.Pending,
737             "Deleting service path via renderer");
738         sendNotificationsWithPathDescription(
739             ServicePathNotificationTypes.ServiceDelete,
740             serviceName,
741             RpcStatusEx.Successful,
742             OPERATION_SUCCESSFUL,
743             pathDescription,
744             createLinkForNotif(
745                 deviceRendering(
746                         new RollbackProcessor(),
747                         servicePathInputDataAtoZ,
748                         servicePathInputDataZtoA)
749                     .stream()
750                     .flatMap(rr -> rr.getOtnLinkTps().stream())
751                     .collect(Collectors.toList())),
752             null,
753             serviceType);
754         return true;
755     }
756
757     @SuppressFBWarnings(
758         value = "UPM_UNCALLED_PRIVATE_METHOD",
759         justification = "call in call() method")
760     private boolean manageOtnServicePathCreation(
761             ServiceImplementationRequestInput input,
762             String serviceType,
763             Uint32 serviceRate) {
764         // Rollback should be same for all conditions, so creating a new one
765         RollbackProcessor rollbackProcessor = new RollbackProcessor();
766         List<OtnDeviceRenderingResult> renderingResults =
767             otnDeviceRendering(
768                 rollbackProcessor,
769                 // This is A-Z side
770                 ModelMappingUtils
771                     .rendererCreateOtnServiceInput(
772                         input.getServiceName(),
773                         Action.Create,
774                         input.getServiceAEnd().getServiceFormat().getName(),
775                         serviceRate,
776                         input.getPathDescription(),
777                         true),
778                 // This is Z-A side
779                 ModelMappingUtils
780                     .rendererCreateOtnServiceInput(
781                         input.getServiceName(),
782                         Action.Create,
783                         input.getServiceZEnd().getServiceFormat().getName(),
784                         serviceRate,
785                         input.getPathDescription(),
786                         false),
787                 serviceType);
788         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
789             rollbackProcessor.rollbackAll();
790             sendNotifications(
791                 ServicePathNotificationTypes.ServiceImplementationRequest,
792                 input.getServiceName(),
793                 RpcStatusEx.Failed,
794                 DEVICE_RENDERING_ROLL_BACK_MSG);
795             return false;
796         }
797         sendNotificationsWithPathDescription(
798             ServicePathNotificationTypes.ServiceImplementationRequest,
799             input.getServiceName(),
800             RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
801             input.getPathDescription(),
802             createLinkForNotif(
803                 renderingResults.stream()
804                     .flatMap(rr -> rr.getOtnLinkTps().stream())
805                     .collect(Collectors.toList())),
806             getSupportedLinks(
807                 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
808                 serviceType),
809             serviceType);
810         return true;
811     }
812
813     @SuppressFBWarnings(
814         value = "UPM_UNCALLED_PRIVATE_METHOD",
815         justification = "call in call() method")
816     private boolean manageOtnServicePathDeletion(
817             String serviceName,
818             PathDescription pathDescription,
819             Services service,
820             String serviceType) {
821         LOG.info("Deleting otn-service path {} via renderer", serviceName);
822         sendNotifications(
823                 ServicePathNotificationTypes.ServiceDelete,
824                 serviceName,
825                 RpcStatusEx.Pending,
826                 "Deleting otn-service path via renderer");
827         List<OtnDeviceRenderingResult> renderingResults =
828             otnDeviceRendering(
829                 new RollbackProcessor(),
830                 // This is A-Z side
831                 ModelMappingUtils
832                     .rendererCreateOtnServiceInput(
833                         serviceName,
834                         Action.Delete,
835                         service.getServiceAEnd().getServiceFormat().getName(),
836                         service.getServiceAEnd().getServiceRate(),
837                         pathDescription,
838                         true),
839                 // This is Z-A side
840                 ModelMappingUtils
841                     .rendererCreateOtnServiceInput(
842                         serviceName,
843                         Action.Delete,
844                         service.getServiceZEnd().getServiceFormat().getName(),
845                         service.getServiceAEnd().getServiceRate(),
846                         pathDescription,
847                         false),
848                 serviceType);
849         sendNotificationsWithPathDescription(
850             ServicePathNotificationTypes.ServiceDelete,
851             serviceName,
852             RpcStatusEx.Successful,
853             OPERATION_SUCCESSFUL,
854             pathDescription,
855             createLinkForNotif(
856                 renderingResults.stream()
857                     .flatMap(rr -> rr.getOtnLinkTps().stream())
858                     .collect(Collectors.toList())),
859             getSupportedLinks(
860                 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
861                 serviceType),
862             serviceType);
863         return true;
864     }
865
866     /**
867      * Send renderer notification.
868      * @param servicePathNotificationTypes ServicePathNotificationTypes
869      * @param serviceName String
870      * @param rpcStatusEx RpcStatusEx
871      * @param message String
872      */
873     private void sendNotifications(
874             ServicePathNotificationTypes servicePathNotificationTypes,
875             String serviceName,
876             RpcStatusEx rpcStatusEx,
877             String message) {
878
879         notification.send(
880             servicePathNotificationTypes,
881             serviceName,
882             rpcStatusEx,
883             message
884         );
885     }
886
887     /**
888      * Send renderer notification with path description information.
889      * @param servicePathNotificationTypes ServicePathNotificationTypes
890      * @param serviceName String
891      * @param rpcStatusEx RpcStatusEx
892      * @param message String
893      * @param pathDescription PathDescription
894      */
895     private void sendNotificationsWithPathDescription(
896             ServicePathNotificationTypes servicePathNotificationTypes,
897             String serviceName,
898             RpcStatusEx rpcStatusEx,
899             String message,
900             PathDescription pathDescription,
901             Link notifLink,
902             Set<String> supportedLinks,
903             String serviceType) {
904
905         notification.send(
906             notification.buildNotification(
907                 servicePathNotificationTypes,
908                 serviceName,
909                 rpcStatusEx,
910                 message,
911                 pathDescription,
912                 notifLink,
913                 supportedLinks,
914                 serviceType
915             )
916         );
917     }
918
919     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
920         return
921             otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
922                 ? null
923                 : new LinkBuilder()
924                     .setATermination(
925                         new ATerminationBuilder()
926                             .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
927                             .setTpId(otnLinkTerminationPoints.get(0).getTpId())
928                             .build())
929                     .setZTermination(
930                         new ZTerminationBuilder()
931                             .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
932                             .setTpId(otnLinkTerminationPoints.get(1).getTpId())
933                             .build())
934                     .build();
935     }
936
937     private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
938         //TODO a Map might be more indicated here
939         switch (serviceType) {
940             case StringConstants.SERVICE_TYPE_10GE:
941             case StringConstants.SERVICE_TYPE_1GE:
942                 return allSupportLinks.stream()
943                     .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
944             case StringConstants.SERVICE_TYPE_100GE_M:
945                 return allSupportLinks.stream()
946                     .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
947             case StringConstants.SERVICE_TYPE_ODU4:
948             case StringConstants.SERVICE_TYPE_100GE_S:
949                 return allSupportLinks.stream()
950                     .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
951             case StringConstants.SERVICE_TYPE_ODUC4:
952                 return allSupportLinks.stream()
953                     .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());
954             default:
955                 return null;
956         }
957     }
958 }