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