Manage ODU4 services over multiple OTU4
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / OtnDeviceRendererServiceImpl.java
1 /*
2  * Copyright © 2019 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 java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.HashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.concurrent.ConcurrentLinkedQueue;
18 import java.util.concurrent.CopyOnWriteArrayList;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ForkJoinPool;
21 import java.util.concurrent.ForkJoinTask;
22 import java.util.concurrent.atomic.AtomicBoolean;
23 import org.opendaylight.transportpce.common.StringConstants;
24 import org.opendaylight.transportpce.common.crossconnect.CrossConnect;
25 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
26 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException;
27 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces;
28 import org.opendaylight.transportpce.networkmodel.service.NetworkModelService;
29 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmInterfaceFactory;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathOutput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathOutputBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.az.api.info.AEndApiInfo;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.az.api.info.ZEndApiInfo;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.OpucnTribSlotDef;
36 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
37 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTpBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterface;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterfaceBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.node.interfaces.NodeInterfaceKey;
41 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.otn.renderer.nodes.Nodes;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46 public class OtnDeviceRendererServiceImpl implements OtnDeviceRendererService {
47     private static final Logger LOG = LoggerFactory.getLogger(OtnDeviceRendererServiceImpl.class);
48     private static final String PT_03 = "03";
49     private static final String PT_07 = "07";
50     private final OpenRoadmInterfaceFactory openRoadmInterfaceFactory;
51     private final CrossConnect crossConnect;
52     private final OpenRoadmInterfaces openRoadmInterfaces;
53     private final DeviceTransactionManager deviceTransactionManager;
54     private final NetworkModelService networkModelService;
55
56     public OtnDeviceRendererServiceImpl(OpenRoadmInterfaceFactory openRoadmInterfaceFactory, CrossConnect crossConnect,
57                                         OpenRoadmInterfaces openRoadmInterfaces,
58                                         DeviceTransactionManager deviceTransactionManager,
59                                         NetworkModelService networkModelService) {
60         this.openRoadmInterfaceFactory = openRoadmInterfaceFactory;
61         this.crossConnect = crossConnect;
62         this.openRoadmInterfaces = openRoadmInterfaces;
63         this.deviceTransactionManager = deviceTransactionManager;
64         this.networkModelService = networkModelService;
65     }
66
67 //TODO Align log messages and returned results messages
68     @Override
69     public OtnServicePathOutput setupOtnServicePath(OtnServicePathInput input, String serviceType) {
70         LOG.info("Calling setup otn-service path");
71         if (input.getServiceFormat() == null || input.getServiceRate() == null) {
72             return new OtnServicePathOutputBuilder()
73                 .setSuccess(false)
74                 .setResult("Error - service-type and service-rate must be present")
75                 .build();
76         }
77         List<NodeInterface> nodeInterfaces = new ArrayList<>();
78         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
79         try {
80             switch (serviceType) {
81                 case StringConstants.SERVICE_TYPE_1GE:
82                 case StringConstants.SERVICE_TYPE_10GE:
83                 case StringConstants.SERVICE_TYPE_100GE_M:
84                     LOG.info("Calling Node interfaces {} {} {} {} {} {} {}",
85                         input.getServiceRate(), input.getEthernetEncoding(),
86                         input.getServiceFormat(), input.getOperation(), input.getTribPortNumber(),
87                         input.getTribSlot(), input.getNodes());
88                     if (input.getNodes() != null) {
89                         createLowOrderInterfaces(input, nodeInterfaces, otnLinkTps);
90                         LOG.info("Node interfaces created just fine ");
91                     }
92                     break;
93                 case StringConstants.SERVICE_TYPE_ODU4:
94                     createHighOrderInterfaces(input, nodeInterfaces, otnLinkTps);
95                     break;
96                 case StringConstants.SERVICE_TYPE_ODUC4:
97                     createOduc4TtpInterface(input, nodeInterfaces, otnLinkTps);
98                     break;
99                 case StringConstants.SERVICE_TYPE_100GE_S:
100                     LOG.info("Calling Node interface for service-type {}", serviceType);
101                     if (input.getNodes() != null) {
102                         createHighOrderInterfaces(input, nodeInterfaces, otnLinkTps);
103                         LOG.info("Node interfaces created");
104                     }
105                     break;
106                 default:
107                     LOG.error("Service-type {} not managed yet", serviceType);
108                     return new OtnServicePathOutputBuilder()
109                         .setSuccess(false)
110                         .setResult("Service-type not managed")
111                         .build();
112             }
113         } catch (OpenRoadmInterfaceException e) {
114             LOG.warn("Service path set-up failed", e);
115             Map<NodeInterfaceKey,NodeInterface> nodeInterfacesMap = new HashMap<>();
116             for (NodeInterface nodeInterface : nodeInterfaces) {
117                 if (nodeInterface != null) {
118                     nodeInterfacesMap.put(nodeInterface.key(), nodeInterface);
119                 }
120             }
121             //TODO check if we need to set a NodeInterface Map in the result in that case
122             return new OtnServicePathOutputBuilder()
123                     .setSuccess(false)
124                     .setNodeInterface(nodeInterfacesMap)
125                     .setResult("Service path set-up failed")
126                     .setLinkTp(otnLinkTps)
127                     .build();
128         }
129         LOG.info("Service path set-up succeed");
130         List<String> results = new ArrayList<>();
131         Map<NodeInterfaceKey,NodeInterface> nodeInterfacesMap = new HashMap<>();
132         for (NodeInterface nodeInterface : nodeInterfaces) {
133             if (nodeInterface != null) {
134                 results.add("Otn Service path was set up successfully for node :" + nodeInterface.getNodeId());
135                 nodeInterfacesMap.put(nodeInterface.key(), nodeInterface);
136             }
137         }
138         return new OtnServicePathOutputBuilder()
139                 .setSuccess(true)
140                 .setNodeInterface(nodeInterfacesMap)
141                 .setResult(String.join("\n", results))
142                 .setLinkTp(otnLinkTps)
143                 .build();
144     }
145
146     @SuppressWarnings("rawtypes")
147     // FIXME check if the ForkJoinTask raw type can be avoided
148     // Raw types use are discouraged since they lack type safety.
149     // Resulting Problems are observed at run time and not at compile time
150     public OtnServicePathOutput deleteOtnServicePath(OtnServicePathInput input, String serviceType) {
151         if (input.getNodes() == null) {
152             LOG.error("Unable to delete otn service path. input nodes = null");
153             return new OtnServicePathOutputBuilder()
154                 .setResult("Unable to delete otn service path. input nodes = null")
155                 .setSuccess(false)
156                 .build();
157         }
158         List<Nodes> nodes = input.getNodes();
159         AtomicBoolean success = new AtomicBoolean(true);
160         ConcurrentLinkedQueue<String> results = new ConcurrentLinkedQueue<>();
161         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
162         ForkJoinPool forkJoinPool = new ForkJoinPool();
163         ForkJoinTask forkJoinTask = forkJoinPool.submit(() -> nodes.parallelStream().forEach(node -> {
164             String nodeId = node.getNodeId();
165             LOG.info("Deleting service setup on node {}", nodeId);
166             String networkTp = node.getNetworkTp();
167             if (networkTp == null || input.getServiceRate() == null || input.getServiceFormat() == null) {
168                 LOG.error("destination ({}) or service-rate ({}) or service-format ({}) is null.",
169                     networkTp, input.getServiceRate(), input.getServiceFormat());
170                 return;
171             }
172             if (!this.deviceTransactionManager.isDeviceMounted(nodeId)) {
173                 String result = nodeId + " is not mounted on the controller";
174                 results.add(result);
175                 success.set(false);
176                 LOG.warn(result);
177                 forkJoinPool.shutdown();
178                 return;
179                 // TODO should deletion end here?
180             }
181             // if the node is currently mounted then proceed.
182             List<String> interfacesToDelete = new LinkedList<>();
183             String connectionNumber = "";
184             switch (serviceType) {
185                 case StringConstants.SERVICE_TYPE_100GE_S:
186                     connectionNumber = getConnectionNumber(null, node, networkTp, "ODU4");
187                     break;
188                 case StringConstants.SERVICE_TYPE_100GE_M:
189                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU4");
190                     otnLinkTps.add(new LinkTpBuilder()
191                         .setNodeId(nodeId)
192                         .setTpId(networkTp)
193                         .build());
194                     break;
195                 case StringConstants.SERVICE_TYPE_ODU4:
196                     if (node.getClientTp() == null && node.getNetwork2Tp() == null) {
197                         interfacesToDelete.add(networkTp + "-ODU4");
198                         otnLinkTps.add(new LinkTpBuilder()
199                             .setNodeId(nodeId)
200                             .setTpId(networkTp)
201                             .build());
202                     }
203                     if (node.getClientTp() == null && node.getNetwork2Tp() != null) {
204                         interfacesToDelete.add(networkTp + "-ODU4");
205                         interfacesToDelete.add(node.getNetwork2Tp() + "-ODU4");
206                         connectionNumber = getConnectionNumber(null, node, networkTp, "ODU4");
207                     }
208                     break;
209                 case StringConstants.SERVICE_TYPE_ODUC4:
210                     if (node.getClientTp() == null && node.getNetwork2Tp() == null) {
211                         interfacesToDelete.add(networkTp + "-ODUC4");
212                         otnLinkTps.add(new LinkTpBuilder()
213                             .setNodeId(nodeId)
214                             .setTpId(networkTp)
215                             .build());
216                     }
217                     if (node.getClientTp() == null && node.getNetwork2Tp() != null) {
218                         interfacesToDelete.add(networkTp + "-ODUC4");
219                         interfacesToDelete.add(node.getNetwork2Tp() + "-ODUC4");
220                         connectionNumber = getConnectionNumber(null, node, networkTp, "ODUC4");
221                     }
222                     break;
223                 case StringConstants.SERVICE_TYPE_10GE:
224                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU2e");
225                     otnLinkTps.add(new LinkTpBuilder()
226                         .setNodeId(nodeId)
227                         .setTpId(networkTp)
228                         .build());
229                     break;
230                 case StringConstants.SERVICE_TYPE_1GE:
231                     connectionNumber = getConnectionNumber(input.getServiceName(), node, networkTp, "ODU0");
232                     otnLinkTps.add(new LinkTpBuilder()
233                         .setNodeId(nodeId)
234                         .setTpId(networkTp)
235                         .build());
236                     break;
237                 default:
238                     LOG.error("service-type {} not managed yet", serviceType);
239                     String result = serviceType + " is not supported";
240                     results.add(result);
241                     success.set(false);
242                     return;
243             }
244             List<String> intToDelete = this.crossConnect.deleteCrossConnect(nodeId, connectionNumber, true);
245             for (String interf : intToDelete == null ? new ArrayList<String>() : intToDelete) {
246                 if (!this.openRoadmInterfaceFactory.isUsedByOtnXc(nodeId, interf, connectionNumber,
247                         this.deviceTransactionManager)) {
248                     interfacesToDelete.add(interf);
249                     String supportedInterface = this.openRoadmInterfaces.getSupportedInterface(nodeId, interf);
250                     if (supportedInterface == null) {
251                         continue;
252                     }
253                     if ((input.getServiceRate().intValue() == 100 && !supportedInterface.contains("ODUC4"))
254                         || (input.getServiceRate().intValue() != 100 && !supportedInterface.contains("ODU4"))) {
255                         interfacesToDelete.add(supportedInterface);
256                     }
257                 }
258             }
259
260             for (String interfaceId : interfacesToDelete) {
261                 try {
262                     this.openRoadmInterfaces.deleteInterface(nodeId, interfaceId);
263                 } catch (OpenRoadmInterfaceException e) {
264                     String result = String.format("Failed to delete interface %s on node %s!", interfaceId, nodeId);
265                     success.set(false);
266                     LOG.error(result, e);
267                     results.add(result);
268                 }
269             }
270         }));
271         try {
272             forkJoinTask.get();
273         } catch (InterruptedException | ExecutionException e) {
274             LOG.error("Error while deleting service paths!", e);
275             return new OtnServicePathOutputBuilder()
276                 .setResult("Error while deleting service paths!")
277                 .setSuccess(false)
278                 .build();
279         }
280         forkJoinPool.shutdown();
281         return new OtnServicePathOutputBuilder()
282                 .setSuccess(success.get())
283                 .setLinkTp(otnLinkTps)
284                 .setResult(
285                     results.isEmpty()
286                         ? "Request processed"
287                         : String.join("\n", results))
288                 .build();
289     }
290
291     private String getConnectionNumber(String serviceName, Nodes node, String networkTp, String oduType) {
292         List<String> list1 = new ArrayList<>();
293         List<String> list2 = new ArrayList<>(Arrays.asList("x"));
294         if (node.getClientTp() != null) {
295             list1.addAll(Arrays.asList(node.getClientTp(), oduType));
296             list2.addAll(Arrays.asList(networkTp, oduType));
297         } else if (node.getNetwork2Tp() != null) {
298             list1.addAll(Arrays.asList(networkTp, oduType));
299             list2.addAll(Arrays.asList(node.getNetwork2Tp(), oduType));
300         } else {
301             return "";
302         }
303         if (serviceName != null) {
304             list1.add(serviceName);
305             list2.add(serviceName);
306         }
307         list1.addAll(list2);
308         return String.join("-", list1);
309     }
310
311     private Optional<String> postCrossConnect(List<String> createdOduInterfaces, Nodes node)
312             throws OpenRoadmInterfaceException {
313         return this.crossConnect.postOtnCrossConnect(createdOduInterfaces, node);
314     }
315
316     private void createLowOrderInterfaces(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
317             CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
318         for (Nodes node : input.getNodes()) {
319             AEndApiInfo apiInfoA = null;
320             ZEndApiInfo apiInfoZ = null;
321             if (input.getAEndApiInfo() != null && input.getAEndApiInfo().getNodeId().contains(node.getNodeId())) {
322                 apiInfoA = input.getAEndApiInfo();
323             }
324             if (input.getZEndApiInfo() != null && input.getZEndApiInfo().getNodeId().contains(node.getNodeId())) {
325                 apiInfoZ = input.getZEndApiInfo();
326             }
327             // check if the node is mounted or not?
328             List<String> createdEthInterfaces = new ArrayList<>();
329             List<String> createdOduInterfaces = new ArrayList<>();
330             switch (input.getServiceRate().intValue()) {
331                 case 1:
332                     LOG.info("Input service is 1G");
333                     if (node.getClientTp() != null) {
334                         createdEthInterfaces.add(
335                             openRoadmInterfaceFactory.createOpenRoadmEth1GInterface(node.getNodeId(),
336                                 node.getClientTp()));
337                         createdOduInterfaces.add(
338                             // suppporting interface?, payload ?
339                             openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(), node.getClientTp(),
340                                 input.getServiceName(), PT_07, false, input.getTribPortNumber(), input.getTribSlot()));
341                     }
342                     createdOduInterfaces.add(
343                         openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(), node.getNetworkTp(),
344                             input.getServiceName(), PT_07, true, input.getTribPortNumber(), input.getTribSlot()));
345                     linkTpList.add(
346                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
347                     if (node.getNetwork2Tp() != null) {
348                         createdOduInterfaces.add(
349                             // supporting interface? payload ?
350                             openRoadmInterfaceFactory.createOpenRoadmOdu0Interface(node.getNodeId(),
351                                 node.getNetwork2Tp(), input.getServiceName(), PT_07, true, input.getTribPortNumber(),
352                                 input.getTribSlot()));
353                         linkTpList.add(
354                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
355                     }
356                     break;
357                 case 10:
358                     LOG.info("Input service is 10G");
359                     if (node.getClientTp() != null) {
360                         createdEthInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmEth10GInterface(
361                             node.getNodeId(), node.getClientTp()));
362                         createdOduInterfaces.add(
363                             // suppporting interface?, payload ?
364                             openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(),
365                                 node.getClientTp(), input.getServiceName(), false, input.getTribPortNumber(),
366                                 input.getTribSlot(), apiInfoA, apiInfoZ));
367                     }
368                     createdOduInterfaces.add(
369                         // supporting interface? payload ?
370                         openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(), node.getNetworkTp(),
371                             input.getServiceName(), true, input.getTribPortNumber(), input.getTribSlot(), apiInfoA,
372                             apiInfoZ));
373                     linkTpList.add(
374                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
375                     if (node.getNetwork2Tp() != null) {
376                         createdOduInterfaces.add(
377                             // supporting interface? payload ?
378                             openRoadmInterfaceFactory.createOpenRoadmOdu2eInterface(node.getNodeId(),
379                                 node.getNetwork2Tp(), input.getServiceName(), true, input.getTribPortNumber(),
380                                 input.getTribSlot(), apiInfoA, apiInfoZ));
381                         linkTpList.add(
382                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
383                     }
384                     break;
385                 case 100:
386                     LOG.info("Input service is 100G");
387                     // Take the first and last value in the list of OpucnTribSlot (assuming SH would provide
388                     // min and max value only, size two)
389                     OpucnTribSlotDef minOpucnTs = OpucnTribSlotDef.getDefaultInstance(
390                         input.getOpucnTribSlots().get(0).getValue());
391                     OpucnTribSlotDef maxOpucnTs = OpucnTribSlotDef.getDefaultInstance(
392                         input.getOpucnTribSlots().get(1).getValue());
393                     if (node.getClientTp() != null) {
394                         createdEthInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmEth100GInterface(
395                             node.getNodeId(), node.getClientTp()));
396                         // OPUCn trib information is optional when creating ODU4 ethernet (client) interface
397                         createdOduInterfaces.add(
398                             openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
399                             node.getClientTp(), input.getServiceName(), PT_07, false, minOpucnTs,
400                                 maxOpucnTs));
401                     }
402                     // Here payload-type is optional and is not used for interface creation (especially for network)
403                     createdOduInterfaces.add(
404                         openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
405                             node.getNetworkTp(), input.getServiceName(), PT_07, true, minOpucnTs,
406                             maxOpucnTs));
407                     linkTpList.add(
408                         new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
409                     // Here payload-type is optional and is not used for service creation
410                     // This is needed if there is an intermediate node
411                     if (node.getNetwork2Tp() != null) {
412                         createdOduInterfaces.add(
413                             openRoadmInterfaceFactory.createOpenRoadmOtnOdu4LoInterface(node.getNodeId(),
414                                 node.getNetwork2Tp(), input.getServiceName(), PT_07, true, minOpucnTs,
415                                 maxOpucnTs));
416                         linkTpList.add(
417                             new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
418                     }
419                     break;
420                 default:
421                     LOG.error("service rate {} not managed yet", input.getServiceRate());
422                     return;
423             }
424
425             // implement cross connect
426             List<String> createdConnections = new ArrayList<>();
427             if (!createdOduInterfaces.isEmpty()) {
428                 Optional<String> connectionNameOpt = postCrossConnect(createdOduInterfaces, node);
429                 createdConnections.add(connectionNameOpt.get());
430                 LOG.info("Created cross connects");
431             }
432             nodeInterfaces.add(new NodeInterfaceBuilder()
433                     .withKey(new NodeInterfaceKey(node.getNodeId()))
434                     .setNodeId(node.getNodeId())
435                     .setConnectionId(createdConnections)
436                     .setEthInterfaceId(createdEthInterfaces)
437                     .setOduInterfaceId(createdOduInterfaces)
438                     .build());
439         }
440     }
441
442     private void createHighOrderInterfaces(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
443             CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
444         for (Nodes node : input.nonnullNodes()) {
445             AEndApiInfo apiInfoA = null;
446             ZEndApiInfo apiInfoZ = null;
447             if (input.getAEndApiInfo() != null && input.getAEndApiInfo().getNodeId().contains(node.getNodeId())) {
448                 apiInfoA = input.getAEndApiInfo();
449             }
450             if (input.getZEndApiInfo() != null && input.getZEndApiInfo().getNodeId().contains(node.getNodeId())) {
451                 apiInfoZ = input.getZEndApiInfo();
452             }
453             // check if the node is mounted or not?
454             List<String> createdEthInterfaces = new ArrayList<>();
455             List<String> createdOduInterfaces = new ArrayList<>();
456             switch (input.getServiceRate().intValue()) {
457                 case 100:
458                     LOG.info("Input service is 100G");
459                     if (node.getClientTp() != null && node.getNetwork2Tp() == null) {
460                         createdEthInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmEth100GInterface(
461                             node.getNodeId(), node.getClientTp()));
462                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
463                                 node.getNodeId(), node.getClientTp(), false, apiInfoA, apiInfoZ, "21"));
464                         // supporting interface? payload ?
465                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
466                                 node.getNodeId(), node.getNetworkTp(), true, null, null, "21"));
467                         linkTpList.add(new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getClientTp())
468                                 .build());
469                     }
470                     if (node.getClientTp() == null && node.getNetwork2Tp() == null) {
471                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
472                             node.getNodeId(), node.getNetworkTp(), false, apiInfoA, apiInfoZ, "21"));
473                         linkTpList.add(new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp())
474                             .build());
475                     }
476                     if (node.getClientTp() == null && node.getNetwork2Tp() != null) {
477                         // supporting interface? payload ?
478                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
479                             node.getNodeId(), node.getNetworkTp(), true, null, null, "21"));
480                         createdOduInterfaces.add(openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
481                                 node.getNodeId(), node.getNetwork2Tp(), true, null, null, "21"));
482                     }
483                     break;
484                 default:
485                     LOG.error("service rate {} not managed yet", input.getServiceRate());
486                     return;
487             }
488
489             // implement cross connect
490             List<String> createdConnections = new ArrayList<>();
491             if (createdOduInterfaces.size() == 2) {
492                 Optional<String> connectionNameOpt = postCrossConnect(createdOduInterfaces, node);
493                 createdConnections.add(connectionNameOpt.get());
494                 LOG.info("Created cross connects");
495             }
496             nodeInterfaces.add(new NodeInterfaceBuilder()
497                     .withKey(new NodeInterfaceKey(node.getNodeId()))
498                     .setNodeId(node.getNodeId())
499                     .setConnectionId(createdConnections)
500                     .setEthInterfaceId(createdEthInterfaces)
501                     .setOduInterfaceId(createdOduInterfaces)
502                     .build());
503         }
504     }
505
506     private void createOduc4TtpInterface(OtnServicePathInput input, List<NodeInterface> nodeInterfaces,
507         CopyOnWriteArrayList<LinkTp> linkTpList) throws OpenRoadmInterfaceException {
508         if (input.getNodes() == null) {
509             return;
510         }
511         LOG.info("Creation of ODUC4 TTP interface in OTN service path {}", input);
512         for (int i = 0; i < input.getNodes().size(); i++) {
513             Nodes node = input.getNodes().get(i);
514             String supportingOtuInterface = node.getNetworkTp() + "-OTUC4";
515
516             Nodes tgtNode =
517                 i + 1 == input.getNodes().size()
518                 // For the end node, tgtNode becomes the first node in the list
519                     ? input.getNodes().get(0)
520                     : input.getNodes().get(i + 1);
521
522             nodeInterfaces.add(new NodeInterfaceBuilder()
523                     .withKey(new NodeInterfaceKey(node.getNodeId()))
524                     .setNodeId(node.getNodeId())
525                     .setOduInterfaceId(List.of(
526                         // though this is odu, actually it has ODUC4 interfaces
527                         openRoadmInterfaceFactory.createOpenRoadmOtnOduc4Interface(node.getNodeId(),
528                             node.getNetworkTp(), supportingOtuInterface, tgtNode.getNodeId(), tgtNode.getNetworkTp())))
529                     .build());
530             linkTpList.add(new LinkTpBuilder().setNodeId(node.getNodeId()).setTpId(node.getNetworkTp()).build());
531         }
532     }
533 }