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