2 * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.impl.lifecycle;
10 import com.google.common.base.Verify;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Objects;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.TimeUnit;
17 import java.util.concurrent.TimeoutException;
18 import javax.annotation.Nullable;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
21 import org.opendaylight.openflowplugin.api.openflow.OFPManager;
22 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
23 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionStatus;
24 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
25 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
26 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
27 import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChain;
28 import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainHolder;
29 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
30 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
31 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager;
32 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
33 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.ContextChainState;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.openflow.provider.config.ContextChainConfig;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 public class ContextChainHolderImpl implements ContextChainHolder {
41 private static final Logger LOG = LoggerFactory.getLogger(ContextChainHolderImpl.class);
42 private static final String NOT_ALL_MANAGER_WERE_SET = "Not all manager were set.";
43 private static final String MANAGER_WAS_SET = " manager was set";
44 private static final String CONTEXT_CREATED_FOR_CONNECTION = " context created for connection: {}";
45 private static final String SINGLETON_SERVICE_PROVIDER_WAS_NOT_SET_YET
46 = "Singleton service provider was not set yet.";
48 private DeviceManager deviceManager;
49 private RpcManager rpcManager;
50 private StatisticsManager statisticsManager;
51 private ConcurrentHashMap<DeviceInfo, ContextChain> contextChainMap = new ConcurrentHashMap<>();
52 private ConcurrentHashMap<DeviceInfo, ConnectionContext> latestConnections = new ConcurrentHashMap<>();
53 private final ContextChainConfig config;
54 private ClusterSingletonServiceProvider singletonServicesProvider;
56 public ContextChainHolderImpl(final ContextChainConfig config) {
61 public <T extends OFPManager> void addManager(final T manager) {
62 if (Objects.isNull(deviceManager) && manager instanceof DeviceManager) {
63 LOG.info("Device" + MANAGER_WAS_SET);
64 deviceManager = (DeviceManager) manager;
65 } else if (Objects.isNull(rpcManager) && manager instanceof RpcManager) {
66 LOG.info("RPC" + MANAGER_WAS_SET);
67 rpcManager = (RpcManager) manager;
68 } else if (Objects.isNull(statisticsManager) && manager instanceof StatisticsManager) {
69 LOG.info("Statistics" + MANAGER_WAS_SET);
70 statisticsManager = (StatisticsManager) manager;
75 public ContextChain createContextChain(final ConnectionContext connectionContext) {
77 final DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
78 final String deviceInfoLOGValue = deviceInfo.getLOGValue();
80 if (LOG.isDebugEnabled()) {
81 LOG.debug("Creating a new chain" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
84 ContextChain contextChain = new ContextChainImpl();
85 LifecycleService lifecycleService = new LifecycleServiceImpl(this);
87 if (LOG.isDebugEnabled()) {
88 LOG.debug("Lifecycle services" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
91 final DeviceContext deviceContext = deviceManager.createContext(connectionContext);
93 if (LOG.isDebugEnabled()) {
94 LOG.debug("Device" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
97 final RpcContext rpcContext = rpcManager.createContext(connectionContext.getDeviceInfo(), deviceContext);
99 if (LOG.isDebugEnabled()) {
100 LOG.debug("RPC" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
103 final StatisticsContext statisticsContext
104 = statisticsManager.createContext(deviceContext);
106 if (LOG.isDebugEnabled()) {
107 LOG.debug("Statistics" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
110 deviceContext.setLifecycleInitializationPhaseHandler(statisticsContext);
111 statisticsContext.setLifecycleInitializationPhaseHandler(rpcContext);
112 statisticsContext.setInitialSubmitHandler(deviceContext);
114 contextChain.addLifecycleService(lifecycleService);
115 contextChain.addContext(deviceContext);
116 contextChain.addContext(rpcContext);
117 contextChain.addContext(statisticsContext);
118 contextChain.makeDeviceSlave();
125 public ListenableFuture<Void> connectionLost(final DeviceInfo deviceInfo) {
126 if (!this.checkChainContext(deviceInfo)) {
127 return Futures.immediateFuture(null);
133 public void destroyContextChain(final DeviceInfo deviceInfo) {
134 ContextChain chain = contextChainMap.get(deviceInfo);
135 if (Objects.nonNull(chain)) {
138 deviceManager.removeDeviceFromOperationalDS(deviceInfo).checkedGet(5L, TimeUnit.SECONDS);
139 } catch (TimeoutException | TransactionCommitFailedException e) {
140 LOG.warn("Not able to remove device {} from DS", deviceInfo.getLOGValue());
146 public void pairConnection(final ConnectionContext connectionContext) {
147 DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
148 ContextChain contextChain = contextChainMap.get(deviceInfo);
149 if (Objects.nonNull(contextChain)) {
150 contextChain.changePrimaryConnection(connectionContext);
151 contextChain.makeDeviceSlave();
156 public ConnectionStatus deviceConnected(final ConnectionContext connectionContext) throws Exception {
158 Verify.verify(this.checkAllManagers(), NOT_ALL_MANAGER_WERE_SET);
159 Verify.verifyNotNull(this.singletonServicesProvider, SINGLETON_SERVICE_PROVIDER_WAS_NOT_SET_YET);
161 LOG.info("Device {} connected.", connectionContext.getDeviceInfo().getLOGValue());
162 ContextChain chain = contextChainMap.get(connectionContext.getDeviceInfo());
164 if (Objects.isNull(chain)) {
165 contextChainMap.put(connectionContext.getDeviceInfo(), createContextChain(connectionContext));
167 this.pairConnection(connectionContext);
170 return ConnectionStatus.MAY_CONTINUE;
174 public void addSingletonServicesProvider(final ClusterSingletonServiceProvider singletonServicesProvider) {
175 this.singletonServicesProvider = singletonServicesProvider;
179 public void onNotAbleToStartMastership(final DeviceInfo deviceInfo) {
180 ContextChain contextChain = contextChainMap.get(deviceInfo);
181 if (Objects.nonNull(contextChain)) {
182 LOG.warn("Not able to set MASTER role on device {}", deviceInfo.getLOGValue());
183 if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) {
184 contextChain.closePrimaryConnection();
186 contextChain.sleepTheChainAndDropConnection();
192 public void onMasterRoleAcquired(final DeviceInfo deviceInfo) {
193 ContextChain contextChain = contextChainMap.get(deviceInfo);
194 if (Objects.nonNull(contextChain)) {
195 if (contextChain.getContextChainState().equals(ContextChainState.WORKINGMASTER)) {
196 if (LOG.isDebugEnabled()) {
197 LOG.debug("Device {} already working as MASTER no changes need to be done.",
198 deviceInfo.getLOGValue());
201 if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) {
202 LOG.info("Device {} has not finish initial gathering yet.",
203 deviceInfo.getLOGValue());
205 Futures.addCallback(contextChain.startChain(),
206 new StartStopChainCallback(contextChain.provideDeviceContext(), false));
212 public void onSlaveRoleAcquired(final DeviceInfo deviceInfo) {
213 ContextChain contextChain = contextChainMap.get(deviceInfo);
214 if (Objects.nonNull(contextChain)) {
215 // if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) {
216 // contextChain.registerServices(this.singletonServicesProvider);
218 // Futures.addCallback(contextChain.stopChain(false),
219 // new StartStopChainCallback(contextChain.provideDeviceContext(), true));
221 contextChain.registerServices(this.singletonServicesProvider);
226 public void onSlaveRoleNotAcquired(final DeviceInfo deviceInfo) {
227 ContextChain contextChain = contextChainMap.get(deviceInfo);
228 if (Objects.nonNull(contextChain)) {
229 contextChain.sleepTheChainAndDropConnection();
234 public void onDeviceDisconnected(final ConnectionContext connectionContext) {
236 if (Objects.isNull(connectionContext.getDeviceInfo())) {
237 LOG.info("Non existing device info. Cannot close context chain.");
239 LOG.info("Device {} disconnected.", connectionContext.getDeviceInfo().getLOGValue());
240 ContextChain chain = contextChainMap.get(connectionContext.getDeviceInfo());
241 if (Objects.isNull(chain)) {
242 if (LOG.isDebugEnabled()) {
243 LOG.debug("There was no context chain created yet for the disconnected device {}",
244 connectionContext.getDeviceInfo().getLOGValue());
247 Futures.addCallback(chain.connectionDropped(),
248 new StartStopChainCallback(null, true));
253 private boolean checkAllManagers() {
254 return Objects.nonNull(deviceManager) && Objects.nonNull(rpcManager) && Objects.nonNull(statisticsManager);
257 private boolean checkChainContext(final DeviceInfo deviceInfo) {
258 return contextChainMap.containsKey(deviceInfo);
261 private class StartStopChainCallback implements FutureCallback<Void> {
263 private final String deviceInfo;
264 private final String stop;
265 private final String stopped;
266 private final boolean start;
267 private final DeviceContext deviceContext;
269 StartStopChainCallback(final DeviceContext deviceContext, final boolean stop) {
271 this.deviceInfo = Objects.nonNull(deviceContext) ? deviceContext.getDeviceInfo().getLOGValue() : "null";
272 this.stop = stop ? "stop" : "start";
273 this.stopped = stop ? "stopped" : "started";
275 this.deviceContext = deviceContext;
279 public void onSuccess(@Nullable Void aVoid) {
280 LOG.info("Context chain for device {} successfully {}", deviceInfo, stopped);
281 // if (start && Objects.nonNull(deviceContext)) {
282 // deviceContext.masterSuccessful();
287 public void onFailure(Throwable throwable) {
288 LOG.warn("Not able to {} the context chain for device {}", stop, deviceInfo);