Migration to TAPI 2.4 Step3
[transportpce.git] / tapi / src / main / java / org / opendaylight / transportpce / tapi / listeners / TapiNetworkModelNotificationHandler.java
1 /*
2  * Copyright © 2021 Nokia, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.tapi.listeners;
9
10 import java.nio.charset.StandardCharsets;
11 import java.time.OffsetDateTime;
12 import java.time.ZoneOffset;
13 import java.time.format.DateTimeFormatter;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Objects;
21 import java.util.Optional;
22 import java.util.Set;
23 import java.util.UUID;
24 import java.util.concurrent.ExecutionException;
25 import java.util.stream.Collectors;
26 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
27 import org.opendaylight.mdsal.binding.api.NotificationService.CompositeListener;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
30 import org.opendaylight.transportpce.tapi.TapiStringConstants;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
32 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.PublishTapiNotificationService;
33 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230728.PublishTapiNotificationServiceBuilder;
34 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.AdministrativeState;
35 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.Context;
36 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.DateAndTime;
37 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.LayerProtocolName;
38 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.OperationalState;
39 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.Uuid;
40 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.global._class.Name;
41 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.global._class.NameKey;
42 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.CONNECTIVITYOBJECTTYPECONNECTIVITYSERVICE;
43 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.OwnedNodeEdgePoint1;
44 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connection.LowerConnection;
45 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.Connection;
46 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.ConnectionBuilder;
47 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.ConnectionKey;
48 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.ConnectivityService;
49 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.ConnectivityServiceBuilder;
50 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.connectivity.context.ConnectivityServiceKey;
51 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext;
52 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.NOTIFICATIONTYPEATTRIBUTEVALUECHANGE;
53 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.NameAndValueChange;
54 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.Notification;
55 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.ChangedAttributes;
56 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.ChangedAttributesBuilder;
57 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.ChangedAttributesKey;
58 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.TargetObjectName;
59 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.TargetObjectNameBuilder;
60 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev221121.notification.TargetObjectNameKey;
61 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.Context1;
62 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.NodeEdgePointRef;
63 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.TOPOLOGYOBJECTTYPENODEEDGEPOINT;
64 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.context.TopologyContext;
65 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.node.OwnedNodeEdgePoint;
66 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.node.OwnedNodeEdgePointKey;
67 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.Node;
68 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.NodeKey;
69 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.context.Topology;
70 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.context.TopologyKey;
71 import org.opendaylight.yangtools.yang.binding.EnumTypeObject;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.osgi.service.component.annotations.Activate;
74 import org.osgi.service.component.annotations.Component;
75 import org.osgi.service.component.annotations.Reference;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 @Component(service = TapiNetworkModelNotificationHandler.class)
80 public class TapiNetworkModelNotificationHandler {
81
82     private static final Logger LOG = LoggerFactory.getLogger(TapiNetworkModelNotificationHandler.class);
83     private final NetworkTransactionService networkTransactionService;
84     private final NotificationPublishService notificationPublishService;
85     private final List<ConnectivityService> connectivityServiceChanges = new ArrayList<>();
86     private final Uuid tapiTopoUuid = new Uuid(UUID.nameUUIDFromBytes(TapiStringConstants.T0_FULL_MULTILAYER
87             .getBytes(StandardCharsets.UTF_8)).toString());
88     private final List<LayerProtocolName> orderedServiceLayerList;
89
90     @Activate
91     public TapiNetworkModelNotificationHandler(@Reference NetworkTransactionService networkTransactionService,
92             @Reference NotificationPublishService notificationPublishService) {
93         this.networkTransactionService = networkTransactionService;
94         this.notificationPublishService = notificationPublishService;
95         this.orderedServiceLayerList = List.of(LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.ODU,
96             LayerProtocolName.DSR, LayerProtocolName.ETH);
97         LOG.debug("TapiNetworkModelListenerImpl instantiated");
98     }
99
100     public CompositeListener getCompositeListener() {
101         return new CompositeListener(Set.of(
102             new CompositeListener.Component<>(Notification.class, this::onNotification)));
103     }
104
105     private void onNotification(Notification notification) {
106         LOG.info("Received network model notification {}", notification);
107         if (notification.getNotificationType().equals(NOTIFICATIONTYPEATTRIBUTEVALUECHANGE.VALUE)
108                 && notification.getTargetObjectType().equals(TOPOLOGYOBJECTTYPENODEEDGEPOINT.VALUE)) {
109             if (notification.getChangedAttributes() == null) {
110                 return;
111             }
112             // TODO: need to re-think this to update first the connections from roadm to roadm and then the others
113             updateConnections(notification.getChangedAttributes().keySet().stream()
114                     .map(changedAttributesKey -> new Uuid(changedAttributesKey.getValueName()))
115                     .collect(Collectors.toList()), notification.getChangedAttributes().values().stream()
116                     .map(NameAndValueChange::getNewValue)
117                     .collect(Collectors.toList()));
118             updateConnectivityServices();
119             // todo set attributes
120             for (ConnectivityService connService : this.connectivityServiceChanges) {
121                 sendNbiNotification(createNbiNotification(connService));
122             }
123         }
124     }
125
126 //    @Override
127 //    public void onEventNotification(EventNotification notification) {
128 //        LOG.info("Received network model notification {}", notification);
129 //        //TODO: see if implementation needed and if in TAPI2.4, something supersedes this method
130 //    }
131
132     private PublishTapiNotificationService createNbiNotification(ConnectivityService connService) {
133         if (connService == null) {
134             LOG.error("ConnService is null");
135             return null;
136         }
137         Map<ChangedAttributesKey, ChangedAttributes> changedStates = new HashMap<>();
138         changedStates.put(new ChangedAttributesKey("administrativeState"),
139             new ChangedAttributesBuilder()
140                 .setNewValue(connService.getAdministrativeState().getName())
141                 .setOldValue(connService.getAdministrativeState().equals(AdministrativeState.UNLOCKED)
142                     ? AdministrativeState.LOCKED.getName() : AdministrativeState.UNLOCKED.getName())
143                 .setValueName("administrativeState").build());
144         changedStates.put(new ChangedAttributesKey("operationalState"),
145             new ChangedAttributesBuilder()
146                 .setNewValue(connService.getOperationalState().getName())
147                 .setOldValue(connService.getOperationalState().equals(OperationalState.ENABLED)
148                     ? OperationalState.DISABLED.getName() : OperationalState.ENABLED.getName())
149                 .setValueName("operationalState").build());
150         DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
151         OffsetDateTime offsetDateTime = OffsetDateTime.now(ZoneOffset.UTC);
152         DateAndTime datetime = new DateAndTime(dtf.format(offsetDateTime));
153         Map<TargetObjectNameKey, TargetObjectName> targetObjectNames = new HashMap<>();
154         if (connService.getName() != null) {
155             for (Map.Entry<NameKey, Name> entry : connService.getName().entrySet()) {
156                 targetObjectNames.put(new TargetObjectNameKey(entry.getKey().getValueName()),
157                     new TargetObjectNameBuilder()
158                         .setValueName(entry.getValue().getValueName())
159                         .setValue(entry.getValue().getValue())
160                         .build());
161             }
162         }
163
164         return new PublishTapiNotificationServiceBuilder()
165             .setUuid(new Uuid(UUID.randomUUID().toString()))
166             .setTopic(connService.getUuid().getValue())
167             .setTargetObjectIdentifier(connService.getUuid())
168             .setNotificationType(NOTIFICATIONTYPEATTRIBUTEVALUECHANGE.VALUE)
169             .setChangedAttributes(changedStates)
170             .setEventTimeStamp(datetime)
171             .setTargetObjectName(targetObjectNames)
172             .setTargetObjectType(CONNECTIVITYOBJECTTYPECONNECTIVITYSERVICE.VALUE)
173             .setLayerProtocolName(connService.getLayerProtocolName())
174             .build();
175     }
176
177     private void sendNbiNotification(PublishTapiNotificationService service) {
178         try {
179             this.notificationPublishService.putNotification(service);
180         } catch (InterruptedException e) {
181             LOG.warn("Cannot send notification to nbi", e);
182             Thread.currentThread().interrupt();
183         }
184     }
185
186     private void updateConnectivityServices() {
187         try {
188             this.connectivityServiceChanges.clear();
189             InstanceIdentifier<ConnectivityContext> connectivityContextIID =
190                 InstanceIdentifier.builder(Context.class).augmentation(
191                         org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
192                     .child(ConnectivityContext.class)
193                     .build();
194             Optional<ConnectivityContext> optConnContext =
195                 this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivityContextIID).get();
196             if (optConnContext.isEmpty()) {
197                 LOG.error("Could not update TAPI connectivity services");
198                 return;
199             }
200             ConnectivityContext connContext = optConnContext.orElseThrow();
201             Map<Uuid, EnumTypeObject[]> states = new HashMap<>();
202             if (connContext.getConnectivityService() == null) {
203                 return;
204             }
205             for (ConnectivityService connService : connContext.getConnectivityService().values()) {
206                 LOG.info("Connectivity service = {}", connService);
207                 // TODO: maybe we need to check lower connections if my new code doesnt work
208                 states.put(connService.getUuid(), getStates(connService));
209                 AdministrativeState adminState = (AdministrativeState) states.get(connService.getUuid())[0];
210                 OperationalState operState = (OperationalState) states.get(connService.getUuid())[1];
211
212                 InstanceIdentifier<ConnectivityService> connServIID = InstanceIdentifier
213                     .builder(Context.class).augmentation(org.opendaylight.yang.gen.v1
214                                 .urn.onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
215                     .child(ConnectivityContext.class)
216                     .child(ConnectivityService.class, new ConnectivityServiceKey(connService.getUuid()))
217                     .build();
218                 ConnectivityService changedConnServ = new ConnectivityServiceBuilder()
219                     .setUuid(connService.getUuid())
220                     .setAdministrativeState(adminState)
221                     .setOperationalState(operState)
222                     .build();
223                 this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connServIID,
224                     changedConnServ);
225                 this.networkTransactionService.commit().get();
226
227                 if (connService.getAdministrativeState() != adminState
228                     || connService.getOperationalState() != operState) {
229                     this.connectivityServiceChanges.add(changedConnServ);
230                 }
231             }
232             // TODO: this last function may need some refactoring... if the PHOT_MEDIA goes down,
233             //  then ODU goes down and then DSR should also go down
234             for (ConnectivityService connService : connContext.getConnectivityService().values()) {
235                 AdministrativeState adminState = (AdministrativeState) states.get(connService.getUuid())[0];
236                 OperationalState operState = (OperationalState) states.get(connService.getUuid())[1];
237                 this.connectivityServiceChanges.addAll(updateSupportedConnectivityServices(
238                     connContext.getConnectivityService().values(), connService.getUuid(), adminState, operState,
239                     LayerProtocolName.ODU));
240             }
241         } catch (InterruptedException | ExecutionException e) {
242             LOG.error("Could not update TAPI connectivity services");
243         }
244     }
245
246     private EnumTypeObject[] getStates(ConnectivityService connService)
247             throws InterruptedException, ExecutionException {
248         OperationalState operState = OperationalState.ENABLED;
249         AdministrativeState adminState = AdministrativeState.UNLOCKED;
250         if (connService.getConnection() == null) {
251             LOG.info("No connections on service = {}", connService);
252             return new EnumTypeObject[]{null, null};
253         }
254         for (org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121
255                 .connectivity.service.Connection connection : connService.getConnection().values()) {
256             InstanceIdentifier<Connection> connIID =
257                 InstanceIdentifier.builder(Context.class).augmentation(org.opendaylight.yang.gen.v1.urn
258                         .onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
259                     .child(ConnectivityContext.class)
260                     .child(Connection.class, new ConnectionKey(connection.getConnectionUuid()))
261                     .build();
262             Optional<Connection> optConn = this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL,
263                 connIID).get();
264             if (optConn.isEmpty()) {
265                 LOG.error("Could not get state for a TAPI connection");
266                 continue;
267             }
268             LOG.info("State of connection {} of connectivity service {} = {}", optConn.orElseThrow().getUuid()
269                 .getValue(), connService.getUuid().getValue(), optConn.orElseThrow().getOperationalState().getName());
270             if (optConn.orElseThrow().getOperationalState() == OperationalState.DISABLED) {
271                 adminState = AdministrativeState.LOCKED;
272                 operState = OperationalState.DISABLED;
273             }
274         }
275         return new EnumTypeObject[]{adminState, operState};
276     }
277
278     private void updateConnections(List<Uuid> changedOneps, List<String> onepStates) {
279         LOG.info("Updating TAPI connections");
280         LOG.info("Change in oneps = {}, new states = {}", changedOneps, onepStates);
281         try {
282             //should it return a list of connections?
283             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn
284                     .onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext> connectivityContextIID =
285                 InstanceIdentifier.builder(Context.class).augmentation(
286                             org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
287                         .child(org.opendaylight.yang.gen.v1.urn
288                                 .onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext.class)
289                         .build();
290             Optional<org.opendaylight.yang.gen.v1.urn
291                     .onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext> optConnContext =
292                 this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivityContextIID).get();
293             if (optConnContext.isEmpty()) {
294                 LOG.error(TapiStringConstants.TAPI_CONNECTION_UPDATE_ERROR);
295                 return;
296             }
297             if (optConnContext.orElseThrow().getConnectivityService() == null) {
298                 LOG.info("No TAPI connectivity service to update");
299                 return;
300             }
301             // TODO: order services from lower layer to upper layer
302             Map<ConnectivityServiceKey, ConnectivityService> connServMap
303                     = optConnContext.orElseThrow().getConnectivityService();
304             if (connServMap == null) {
305                 LOG.info("No connections to update");
306                 return;
307             }
308             connServMap = orderConnServiceMap(connServMap);
309             for (ConnectivityService connService : connServMap.values()) {
310                 LOG.info("Looping through connectivity service = {}", connService.getUuid().getValue());
311                 if (connService.getConnection() == null) {
312                     continue;
313                 }
314                 for (org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121
315                         .connectivity.service.Connection connection : connService.getConnection().values()) {
316                     InstanceIdentifier<Connection> connIID =
317                         InstanceIdentifier.builder(Context.class).augmentation(org.opendaylight.yang.gen.v1.urn
318                             .onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
319                                 .child(org.opendaylight.yang.gen.v1.urn
320                                         .onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext.class)
321                                 .child(Connection.class, new ConnectionKey(connection.getConnectionUuid()))
322                                 .build();
323                     Optional<Connection> optConn =
324                         this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connIID).get();
325                     if (optConn.isEmpty()) {
326                         LOG.error(TapiStringConstants.TAPI_CONNECTION_READ_ERROR);
327                         continue;
328                     }
329                     Connection newConn = optConn.orElseThrow();
330                     // Check LowerConnection states and if any of the lower connection is disabled then we can put
331                     // the connection out of service. And based on the connection previous state we decide
332                     // the update necessary
333                     OperationalState newConnState = newConn.getOperationalState();
334                     if (newConn.getLowerConnection() != null) {
335                         newConnState = updateLowerConnections(changedOneps, onepStates,
336                                 newConn.getLowerConnection().values(), newConn.getOperationalState());
337                     }
338                     if (newConnState.equals(newConn.getOperationalState())) {
339                         // To check if the oneps are from the original Top connection
340                         newConnState = getConnectionState(changedOneps, onepStates, newConn);
341                     }
342                     LOG.debug("Analysing connection = {} ", newConn.getName().toString());
343                     LOG.info("Previous connection state = {} & New connection state = {}",
344                             newConn.getOperationalState().getName(), newConnState.getName());
345                     Connection changedConn = new ConnectionBuilder(newConn).setOperationalState(newConnState).build();
346                     // TODO: the changed NEP is a DEG port which is not in any connection,
347                     //  therefore we also need to change the cross connections,
348                     //  the lower connections uuid and check the states.
349                     //  If any of the lower connections of a connection is DISABLED then the top connection is DISABLED
350                     this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connIID, changedConn);
351                     this.networkTransactionService.commit().get();
352                 }
353             }
354         } catch (InterruptedException | ExecutionException e) {
355             LOG.error(TapiStringConstants.TAPI_CONNECTION_UPDATE_ERROR);
356         }
357     }
358
359     private Map<ConnectivityServiceKey, ConnectivityService> orderConnServiceMap(
360             Map<ConnectivityServiceKey, ConnectivityService> connServMap) {
361         Map<ConnectivityServiceKey, ConnectivityService> orderedServiceMap = new HashMap<>();
362         for (LayerProtocolName lpn:this.orderedServiceLayerList) {
363             for (ConnectivityService connServ:connServMap.values()) {
364                 if (connServ.getLayerProtocolName().equals(lpn)) {
365                     LOG.info("Layer of service is equal to entry of lpn = {}", lpn);
366                     orderedServiceMap.put(connServ.key(), connServ);
367                 }
368             }
369         }
370         LOG.info("Ordered map of services = {}", orderedServiceMap);
371         return orderedServiceMap;
372     }
373
374     private OperationalState updateLowerConnections(List<Uuid> changedOneps, List<String> onepStates,
375                                                     Collection<LowerConnection> lowerConnections,
376                                                     OperationalState uppConnState) {
377         LOG.info("Updating lower connections");
378         OperationalState topConnectionState = uppConnState;
379         Boolean allLowerConnEna = true;
380         try {
381             for (LowerConnection lowerConn:lowerConnections) {
382                 InstanceIdentifier<Connection> connIID =
383                     InstanceIdentifier.builder(Context.class).augmentation(org.opendaylight.yang.gen.v1.urn
384                         .onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
385                             .child(org.opendaylight.yang.gen.v1.urn
386                                     .onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext.class)
387                             .child(Connection.class, new ConnectionKey(lowerConn.getConnectionUuid()))
388                             .build();
389                 Optional<Connection> optConn =
390                         this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connIID).get();
391                 if (optConn.isEmpty()) {
392                     LOG.error(TapiStringConstants.TAPI_CONNECTION_READ_ERROR);
393                     continue;
394                 }
395                 Connection newConn = optConn.orElseThrow(); // Current state of connection
396                 if (newConn.getLowerConnection() != null) {
397                     // TODO: we can receive disable here because the lower connection haven been yet looped through and
398                     //  therefore it is disabled but it has to be changed to enable before returning disable.
399                     //  We need to recall the update Lower Connections with the lower connection we are checking now
400                     //  and all its lower connections, until no lower connections are found in the connection
401                     updateLowerConnections(changedOneps, onepStates, newConn.getLowerConnection().values(),
402                             newConn.getOperationalState());
403                 }
404                 OperationalState newConnState = getConnectionState(changedOneps, onepStates, newConn);
405                 // updated connection state if it contains a nep that has changed
406                 if (!newConn.getOperationalState().equals(newConnState)) {
407                     Connection changedConn = new ConnectionBuilder(newConn).setOperationalState(newConnState).build();
408                     this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connIID, changedConn);
409                     this.networkTransactionService.commit().get();
410                 }
411                 if (newConnState.equals(OperationalState.DISABLED)) {
412                     LOG.info("LowerConnection state is disable");
413                     allLowerConnEna = false;
414                     topConnectionState = OperationalState.DISABLED;
415                 }
416             }
417             if (allLowerConnEna) {
418                 return OperationalState.ENABLED;
419             }
420             return OperationalState.DISABLED;
421         } catch (InterruptedException | ExecutionException e) {
422             LOG.error(TapiStringConstants.TAPI_CONNECTION_UPDATE_ERROR);
423             return topConnectionState;
424         }
425     }
426
427     private OperationalState getConnectionState(List<Uuid> changedOneps, List<String> operState, Connection conn)
428             throws InterruptedException, ExecutionException {
429         LOG.info("Getting TAPI connectionState");
430         List<Uuid> connectionNeps = Objects.requireNonNull(conn.getConnectionEndPoint()).values().stream()
431             .map(NodeEdgePointRef::getNodeEdgePointUuid).collect(Collectors.toList());
432         LOG.info("Changed neps = {}", changedOneps);
433         LOG.info("Connection NEPs = {}", connectionNeps);
434         if (!Collections.disjoint(changedOneps, connectionNeps)) {
435             LOG.info("Connection neps {} are included in changed oneps {}", connectionNeps, changedOneps);
436             if ((changedOneps.contains(connectionNeps.get(0)) ? transformOperState(operState.get(
437                     changedOneps.indexOf(connectionNeps.get(0)))) : null) == OperationalState.DISABLED
438                         || (changedOneps.contains(connectionNeps.get(1)) ? transformOperState(operState.get(
439                                 changedOneps.indexOf(connectionNeps.get(1)))) : null) == OperationalState.DISABLED) {
440                 return OperationalState.DISABLED;
441             }
442             LOG.info("Didnt transform correctly the states");
443             for (Uuid connectionNep : connectionNeps) {
444                 Optional<org.opendaylight.yang.gen.v1.urn
445                         .onf.otcc.yang.tapi.connectivity.rev221121.connection.ConnectionEndPoint> ocep
446                     = conn.getConnectionEndPoint().values().stream()
447                         .filter(connectionEndPoint -> connectionEndPoint.getNodeEdgePointUuid() == connectionNep)
448                         .findFirst();
449                 if (ocep.isEmpty()) {
450                     continue;
451                 }
452                 InstanceIdentifier<OwnedNodeEdgePoint> onepIID = InstanceIdentifier.builder(Context.class)
453                     .augmentation(Context1.class).child(TopologyContext.class)
454                     .child(Topology.class, new TopologyKey(tapiTopoUuid))
455                     .child(Node.class, new NodeKey(ocep.orElseThrow().getNodeUuid()))
456                     .child(OwnedNodeEdgePoint.class, new OwnedNodeEdgePointKey(connectionNep))
457                     .build();
458                 Optional<OwnedNodeEdgePoint> onep =
459                     this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, onepIID).get();
460                 if (onep.isEmpty() || onep.orElseThrow().augmentation(OwnedNodeEdgePoint1.class) == null
461                         || onep.orElseThrow().augmentation(OwnedNodeEdgePoint1.class).getCepList() == null) {
462                     continue;
463                 }
464                 if (onep.orElseThrow().getOperationalState() == OperationalState.DISABLED
465                         && !changedOneps.contains(onep.orElseThrow().getUuid())) {
466                     return OperationalState.DISABLED;
467                 }
468             }
469             return OperationalState.ENABLED;
470         }
471         LOG.info("Connection state = {}. Going to check lower connections", conn.getOperationalState());
472         // TODO --> check all lower connections state and if all of them are enabled we return enable, otherwise disable
473         if (conn.getLowerConnection() != null && allLowerConEnabled(conn.getLowerConnection().values())) {
474             return OperationalState.ENABLED;
475         }
476         return conn.getOperationalState();
477     }
478
479     private boolean allLowerConEnabled(Collection<LowerConnection> lowerConnections) {
480         try {
481             for (LowerConnection lowerConn:lowerConnections) {
482                 InstanceIdentifier<Connection> connIID =
483                     InstanceIdentifier.builder(Context.class).augmentation(org.opendaylight.yang.gen.v1.urn
484                             .onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
485                         .child(org.opendaylight.yang.gen.v1.urn
486                             .onf.otcc.yang.tapi.connectivity.rev221121.context
487                             .ConnectivityContext.class)
488                         .child(Connection.class, new ConnectionKey(lowerConn.getConnectionUuid()))
489                         .build();
490                 Optional<Connection> optConn =
491                     this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connIID).get();
492                 if (optConn.isEmpty()) {
493                     LOG.error(TapiStringConstants.TAPI_CONNECTION_READ_ERROR);
494                     continue;
495                 }
496                 Connection newConn = optConn.orElseThrow(); // Current state of connection
497                 // updated connection state if it contains a nep that has changed
498                 if (newConn.getOperationalState().equals(OperationalState.DISABLED)) {
499                     LOG.info("LowerConnection state is disable");
500                     return false;
501                 }
502             }
503             return true;
504         } catch (InterruptedException | ExecutionException e) {
505             LOG.error(TapiStringConstants.TAPI_CONNECTION_UPDATE_ERROR);
506             return false;
507         }
508     }
509
510     private List<ConnectivityService> updateSupportedConnectivityServices(Collection<ConnectivityService> connServices,
511                                                                           Uuid supportingConnService,
512                                                                           AdministrativeState adminState,
513                                                                           OperationalState operState,
514                                                                           LayerProtocolName layer) {
515         // TODO we need to check this function
516         List<ConnectivityService> changedServices = new ArrayList<>();
517         if (adminState != AdministrativeState.LOCKED && operState != OperationalState.DISABLED) {
518             return changedServices;
519         }
520         try {
521             for (ConnectivityService supportedConnService : connServices) {
522                 // TODO currently supporting service uuid is saved in service layer, replace with name as soon
523                 // as name is implemented
524                 if (supportedConnService.getLayerProtocolName() != layer) {
525                     continue;
526                 }
527                 InstanceIdentifier<ConnectivityService> supportedConnServIID = InstanceIdentifier
528                     .builder(Context.class).augmentation(org.opendaylight.yang.gen.v1
529                         .urn.onf.otcc.yang.tapi.connectivity.rev221121.Context1.class)
530                     .child(org.opendaylight.yang.gen.v1
531                         .urn.onf.otcc.yang.tapi.connectivity.rev221121.context.ConnectivityContext.class)
532                     .child(ConnectivityService.class, new ConnectivityServiceKey(supportedConnService.getUuid()))
533                     .build();
534                 Optional<ConnectivityService> optNewConnService = this.networkTransactionService.read(
535                     LogicalDatastoreType.OPERATIONAL, supportedConnServIID).get();
536                 if (optNewConnService.isEmpty()) {
537                     LOG.error("Could not update TAPI connectivity service");
538                     continue;
539                 }
540                 ConnectivityService newConnService = optNewConnService.orElseThrow();
541                 if (supportedConnService.getConnectivityConstraint().getServiceLevel() != null
542                         && supportedConnService.getConnectivityConstraint().getServiceLevel()
543                             .equals(supportingConnService.getValue())
544                         && newConnService.getAdministrativeState() != AdministrativeState.LOCKED
545                         && newConnService.getOperationalState() != OperationalState.DISABLED) {
546
547                     ConnectivityService changedSupportedConnServ = new ConnectivityServiceBuilder()
548                         .setUuid(supportedConnService.getUuid())
549                         .setAdministrativeState(adminState)
550                         .setOperationalState(operState)
551                         .build();
552                     // TODO: may need to update connections...
553                     this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, supportedConnServIID,
554                         changedSupportedConnServ);
555                     this.networkTransactionService.commit().get();
556                     changedServices.add(changedSupportedConnServ);
557                     if (layer == LayerProtocolName.ODU) {
558                         changedServices.addAll(updateSupportedConnectivityServices(connServices,
559                             supportedConnService.getUuid(), adminState, operState, LayerProtocolName.DSR));
560                     }
561                 }
562             }
563         } catch (InterruptedException | ExecutionException e) {
564             LOG.error("Could not update TAPI connectivity service");
565         }
566         return changedServices;
567     }
568
569     private OperationalState transformOperState(String operString) {
570         LOG.debug("Operstring to be converted = {}", operString);
571         State operState = org.opendaylight.transportpce.networkmodel.util.TopologyUtils.setNetworkOperState(operString);
572         LOG.debug("State received from topologyutils = {}", operState);
573         return operState.equals(State.InService) ? OperationalState.ENABLED : OperationalState.DISABLED;
574     }
575
576 }