ddf73a75cc468af369bcfa7fa373c5f024d6c1b2
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / LifecycleConductorImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, 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
9 package org.opendaylight.openflowplugin.impl;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import io.netty.util.HashedWheelTimer;
17 import io.netty.util.Timeout;
18 import io.netty.util.TimerTask;
19 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
20 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
21 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
22 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
23 import org.opendaylight.openflowplugin.api.openflow.lifecycle.DeviceContextChangeListener;
24 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleConductor;
25 import org.opendaylight.openflowplugin.api.openflow.lifecycle.RoleChangeListener;
26 import org.opendaylight.openflowplugin.api.openflow.lifecycle.ServiceChangeListener;
27 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
28 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import javax.annotation.Nonnull;
35 import javax.annotation.Nullable;
36 import java.util.Map;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.TimeUnit;
39
40 /**
41  */
42 public final class LifecycleConductorImpl implements LifecycleConductor, RoleChangeListener, DeviceContextChangeListener {
43
44     private static final Logger LOG = LoggerFactory.getLogger(LifecycleConductorImpl.class);
45     private static final int TICKS_PER_WHEEL = 500;
46     private static final long TICK_DURATION = 10; // 0.5 sec.
47
48     private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(TICK_DURATION, TimeUnit.MILLISECONDS, TICKS_PER_WHEEL);
49     private DeviceManager deviceManager;
50     private final MessageIntelligenceAgency messageIntelligenceAgency;
51     private ConcurrentHashMap<NodeId, ServiceChangeListener> serviceChangeListeners = new ConcurrentHashMap<>();
52     private StatisticsManager statisticsManager;
53
54     public LifecycleConductorImpl(final MessageIntelligenceAgency messageIntelligenceAgency) {
55         Preconditions.checkNotNull(messageIntelligenceAgency);
56         this.messageIntelligenceAgency = messageIntelligenceAgency;
57     }
58
59     public void setSafelyDeviceManager(final DeviceManager deviceManager) {
60         if (this.deviceManager == null) {
61             this.deviceManager = deviceManager;
62         }
63     }
64
65     public void setSafelyStatisticsManager(final StatisticsManager statisticsManager) {
66         if (this.statisticsManager == null) {
67             this.statisticsManager = statisticsManager;
68         }
69     }
70
71     public void addOneTimeListenerWhenServicesChangesDone(final ServiceChangeListener manager, final NodeId nodeId){
72         LOG.debug("Listener {} for service change for node {} registered.", manager, nodeId);
73         serviceChangeListeners.put(nodeId, manager);
74     }
75
76     @VisibleForTesting
77     void notifyServiceChangeListeners(final NodeId nodeId, final boolean success){
78         if (serviceChangeListeners.size() == 0) {
79             return;
80         }
81         LOG.debug("Notifying registered listeners for service change, no. of listeners {}", serviceChangeListeners.size());
82         for (final Map.Entry<NodeId, ServiceChangeListener> nodeIdServiceChangeListenerEntry : serviceChangeListeners.entrySet()) {
83             if (nodeIdServiceChangeListenerEntry.getKey().equals(nodeId)) {
84                 LOG.debug("Listener {} for service change for node {} was notified. Success was set on {}", nodeIdServiceChangeListenerEntry.getValue(), nodeId, success);
85                 nodeIdServiceChangeListenerEntry.getValue().servicesChangeDone(nodeId, success);
86                 serviceChangeListeners.remove(nodeId);
87             }
88         }
89     }
90
91     @Override
92     public void roleInitializationDone(final NodeId nodeId, final boolean success) {
93         if (!success) {
94             LOG.warn("Initialization phase for node {} in role context was NOT successful, closing connection.", nodeId);
95             closeConnection(nodeId);
96         } else {
97             LOG.info("initialization phase for node {} in role context was successful, continuing to next context.", nodeId);
98         }
99     }
100
101     public void closeConnection(final NodeId nodeId) {
102         LOG.debug("Close connection called for node {}", nodeId);
103         final DeviceContext deviceContext = getDeviceContext(nodeId);
104         if (null != deviceContext) {
105             deviceContext.shutdownConnection();
106         }
107     }
108
109     @Override
110     public void roleChangeOnDevice(final NodeId nodeId, final boolean success, final OfpRole newRole, final boolean initializationPhase) {
111
112         final DeviceContext deviceContext = getDeviceContext(nodeId);
113
114         if (null == deviceContext) {
115             LOG.warn("Something went wrong, device context for nodeId: {} doesn't exists");
116             return;
117         }
118         if (!success) {
119             LOG.warn("Role change to {} in role context for node {} was NOT successful, closing connection", newRole, nodeId);
120             closeConnection(nodeId);
121         } else {
122             if (initializationPhase) {
123                 LOG.debug("Initialization phase skipping starting services.");
124                 return;
125             }
126
127             LOG.info("Role change to {} in role context for node {} was successful, starting/stopping services.", newRole, nodeId);
128
129             if (OfpRole.BECOMEMASTER.equals(newRole)) {
130                 statisticsManager.startScheduling(nodeId);
131             } else {
132                 statisticsManager.stopScheduling(nodeId);
133             }
134
135             final ListenableFuture<Void> onClusterRoleChange = deviceContext.onClusterRoleChange(null, newRole);
136             Futures.addCallback(onClusterRoleChange, new FutureCallback<Void>() {
137                 @Override
138                 public void onSuccess(@Nullable final Void aVoid) {
139                     LOG.info("Starting/Stopping services for node {} was successful", nodeId);
140                     if (newRole.equals(OfpRole.BECOMESLAVE)) notifyServiceChangeListeners(nodeId, true);
141                 }
142
143                 @Override
144                 public void onFailure(final Throwable throwable) {
145                     LOG.warn("Starting/Stopping services for node {} was NOT successful, closing connection", nodeId);
146                     closeConnection(nodeId);
147                 }
148             });
149         }
150     }
151
152     public MessageIntelligenceAgency getMessageIntelligenceAgency() {
153         return messageIntelligenceAgency;
154     }
155
156     @Override
157     public DeviceContext getDeviceContext(final NodeId nodeId){
158          return deviceManager.getDeviceContextFromNodeId(nodeId);
159     }
160
161     public Short gainVersionSafely(final NodeId nodeId) {
162         return (null != getDeviceContext(nodeId)) ? getDeviceContext(nodeId).getPrimaryConnectionContext().getFeatures().getVersion() : null;
163     }
164
165     public Timeout newTimeout(@Nonnull TimerTask task, long delay, @Nonnull TimeUnit unit) {
166         return hashedWheelTimer.newTimeout(task, delay, unit);
167     }
168
169     public ConnectionContext.CONNECTION_STATE gainConnectionStateSafely(final NodeId nodeId){
170         return (null != getDeviceContext(nodeId)) ? getDeviceContext(nodeId).getPrimaryConnectionContext().getConnectionState() : null;
171     }
172
173     public Long reserveXidForDeviceMessage(final NodeId nodeId){
174         return null != getDeviceContext(nodeId) ? getDeviceContext(nodeId).reserveXidForDeviceMessage() : null;
175     }
176
177     @Override
178     public void deviceStartInitializationDone(final NodeId nodeId, final boolean success) {
179         if (!success) {
180             LOG.warn("Initialization phase for node {} in device context was NOT successful, closing connection.", nodeId);
181             closeConnection(nodeId);
182         } else {
183             LOG.info("initialization phase for node {} in device context was successful. Continuing to next context.", nodeId);
184         }
185     }
186
187     @Override
188     public void deviceInitializationDone(final NodeId nodeId, final boolean success) {
189         if (!success) {
190             LOG.warn("Initialization phase for node {} in device context was NOT successful, closing connection.", nodeId);
191             closeConnection(nodeId);
192         } else {
193             LOG.info("initialization phase for node {} in device context was successful. All phases initialized OK.", nodeId);
194         }
195     }
196
197     @VisibleForTesting
198     public boolean isServiceChangeListenersEmpty() {
199         return this.serviceChangeListeners.isEmpty();
200     }
201
202 }