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