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