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