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