Merge "Bug 4957 RoleContext updated with initialization"
authormichal rehak <mirehak@cisco.com>
Tue, 9 Feb 2016 09:20:22 +0000 (09:20 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 9 Feb 2016 09:20:22 +0000 (09:20 +0000)
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleContext.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/DeviceInitializationUtils.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java

index 102a7e62575f7213d27c351f27ca6cc154c1f6cd..f1016eacec5800629d581ec0b48089e1c0386944 100644 (file)
@@ -8,14 +8,35 @@
 package org.opendaylight.openflowplugin.api.openflow.role;
 
 import com.google.common.util.concurrent.FutureCallback;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceContextClosedHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
 
 /**
  * Created by kramesha on 9/12/15.
  */
 public interface RoleContext extends RoleChangeListener, DeviceContextClosedHandler, RequestContextStack {
 
+    /**
+     * @deprecated do not use it
+     * @param futureCallback - future
+     */
+    @Deprecated
     void facilitateRoleChange(FutureCallback<Boolean> futureCallback);
 
+    /**
+     * Initialization method is responsible for a registration of
+     * {@link org.opendaylight.controller.md.sal.common.api.clustering.Entity}
+     * and listen for notification from service. {@link Future} returned object is used primary
+     * for new connection initialization phase where we have to wait for actual Role.
+     * The {@link Future} has to be canceled if device is in disconnected state or when
+     * {@link org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService} returns
+     * {@link org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException}
+     * @return InitializationFuture for to know where first initial Election is done and we know role.
+     * @throws CandidateAlreadyRegisteredException - we have registered Entity so drop actual connection
+     */
+    Future<OfpRole> initialization() throws CandidateAlreadyRegisteredException;
+
 }
index 7ddde034304d32e96a097f6d4db5a728021a2798..4908331a52c274ff284839b3dd4ae0edc1019a13 100644 (file)
@@ -120,15 +120,17 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
         });
     }
 
+    @Override
     public boolean isSwitchFeaturesMandatory() {
         return switchFeaturesMandatory;
     }
 
     @Override
-    public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+    public void setEntityOwnershipService(final EntityOwnershipService entityOwnershipService) {
         this.entityOwnershipService = entityOwnershipService;
     }
 
+    @Override
     public void setSwitchFeaturesMandatory(final boolean switchFeaturesMandatory) {
         this.switchFeaturesMandatory = switchFeaturesMandatory;
     }
@@ -170,8 +172,7 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
 
         deviceManager = new DeviceManagerImpl(dataBroker, messageIntelligenceAgency, switchFeaturesMandatory, globalNotificationQuota);
         ((ExtensionConverterProviderKeeper) deviceManager).setExtensionConverterProvider(extensionConverterManager);
-
-        roleManager = new RoleManagerImpl(rpcProviderRegistry, entityOwnershipService);
+        roleManager = new RoleManagerImpl(rpcProviderRegistry, entityOwnershipService, switchFeaturesMandatory);
         statisticsManager = new StatisticsManagerImpl(rpcProviderRegistry, isStatisticsPollingOff);
         rpcManager = new RpcManagerImpl(rpcProviderRegistry, rpcRequestsQuota);
 
@@ -194,12 +195,12 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
     }
 
     private static void registerMXBean(final MessageIntelligenceAgency messageIntelligenceAgency) {
-        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
         try {
-            String pathToMxBean = String.format("%s:type=%s",
+            final String pathToMxBean = String.format("%s:type=%s",
                     MessageIntelligenceAgencyMXBean.class.getPackage().getName(),
                     MessageIntelligenceAgencyMXBean.class.getSimpleName());
-            ObjectName name = new ObjectName(pathToMxBean);
+            final ObjectName name = new ObjectName(pathToMxBean);
             mbs.registerMBean(messageIntelligenceAgency, name);
         } catch (MalformedObjectNameException
                 | NotCompliantMBeanException
index 1decf7ee3db52bf50ee12fdbd92cbfe4a31e8e76..683bb12c661937dbd80aaaf8158903d6c1c4d7c2 100644 (file)
@@ -7,13 +7,7 @@
  */
 package org.opendaylight.openflowplugin.impl.device;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timeout;
+import javax.annotation.Nonnull;
 import java.math.BigInteger;
 import java.util.Collection;
 import java.util.HashMap;
@@ -21,7 +15,14 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import javax.annotation.Nonnull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timeout;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
@@ -118,7 +119,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     private final DataBroker dataBroker;
     private final HashedWheelTimer hashedWheelTimer;
     private final Map<SwitchConnectionDistinguisher, ConnectionContext> auxiliaryConnectionContexts;
-    private final TransactionChainManager transactionChainManager;
+    private TransactionChainManager transactionChainManager;
     private final DeviceFlowRegistry deviceFlowRegistry;
     private final DeviceGroupRegistry deviceGroupRegistry;
     private final DeviceMeterRegistry deviceMeterRegistry;
@@ -147,14 +148,13 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
                       @Nonnull final HashedWheelTimer hashedWheelTimer,
                       @Nonnull final MessageSpy _messageSpy,
                       @Nonnull final OutboundQueueProvider outboundQueueProvider,
-                      @Nonnull final TranslatorLibrary translatorLibrary,
-                      @Nonnull final TransactionChainManager transactionChainManager) {
+            @Nonnull final TranslatorLibrary translatorLibrary) {
         this.primaryConnectionContext = Preconditions.checkNotNull(primaryConnectionContext);
         this.deviceState = Preconditions.checkNotNull(deviceState);
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
         this.hashedWheelTimer = Preconditions.checkNotNull(hashedWheelTimer);
         this.outboundQueueProvider = Preconditions.checkNotNull(outboundQueueProvider);
-        this.transactionChainManager = Preconditions.checkNotNull(transactionChainManager);
+        primaryConnectionContext.setDeviceDisconnectedHandler(DeviceContextImpl.this);
         auxiliaryConnectionContexts = new HashMap<>();
         deviceFlowRegistry = new DeviceFlowRegistryImpl();
         deviceGroupRegistry = new DeviceGroupRegistryImpl();
@@ -180,6 +180,10 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
         itemLifeCycleSourceRegistry.registerLifeCycleSource(flowLifeCycleKeeper);
     }
 
+    void setTransactionChainManager(final TransactionChainManager txChainManager) {
+        this.transactionChainManager = Preconditions.checkNotNull(txChainManager);
+    }
+
     /**
      * This method is called from {@link DeviceManagerImpl} only. So we could say "posthandshake process finish"
      * and we are able to set a scheduler for an automatic transaction submitting by time (0,5sec).
index a38920d5343645795140e630dca7b9a04a3c96da..b5a99013b7ea988a08800e7a08cb60afb88b0f47 100644 (file)
@@ -119,7 +119,7 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
                 //if role = slave
                 try {
                     ((DeviceContextImpl) deviceContext).cancelTransaction();
-                } catch (Exception e) {
+                } catch (final Exception e) {
                     //TODO: how can we avoid it. pingpong does not have cancel
                     LOG.debug("Expected Exception: Cancel Txn exception thrown for slaves", e);
                 }
@@ -140,31 +140,14 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
     @Override
     public void deviceConnected(@CheckForNull final ConnectionContext connectionContext) {
         Preconditions.checkArgument(connectionContext != null);
-
-        ReadyForNewTransactionChainHandler readyForNewTransactionChainHandler = new ReadyForNewTransactionChainHandlerImpl(this, connectionContext);
-        DeviceTransactionChainManagerProvider.TransactionChainManagerRegistration transactionChainManagerRegistration = deviceTransactionChainManagerProvider.provideTransactionChainManager(connectionContext);
-        TransactionChainManager transactionChainManager = transactionChainManagerRegistration.getTransactionChainManager();
-
-        if (transactionChainManagerRegistration.ownedByInvokingConnectionContext()) {
-            //this actually is new registration for currently processed connection context
-            initializeDeviceContext(connectionContext, transactionChainManager);
-        }
-        else if (TransactionChainManager.TransactionChainManagerStatus.WORKING.equals(transactionChainManager.getTransactionChainManagerStatus())) {
-            //this means there already exists connection described by same NodeId and it is not current connection contexts' registration
-            LOG.info("In deviceConnected, ownedByInvokingConnectionContext is false and  TransactionChainManagerStatus.WORKING. Closing connection to device to start again.");
-            connectionContext.closeConnection(false);
-        }
-        else if (!transactionChainManager.attemptToRegisterHandler(readyForNewTransactionChainHandler)) {
-            //previous connection is shutting down, we will try to register handler listening on new transaction chain ready
-            // new connection wil be closed if handler registration fails
-            LOG.info("In deviceConnected, ownedByInvokingConnectionContext is false, TransactionChainManagerStatus is not shutting down or readyForNewTransactionChainHandler is null. " +
-                    "Closing connection to device to start again.");
-            connectionContext.closeConnection(false);
+        try {
+            initializeDeviceContext(connectionContext);
+        } catch (Exception e) {
+            LOG.warn("Exception during initialization phase.", e);
         }
     }
 
-    private void initializeDeviceContext(final ConnectionContext connectionContext,
-            final TransactionChainManager transactionChainManager) {
+    private void initializeDeviceContext(final ConnectionContext connectionContext) throws Exception{
         LOG.info("Initializing New Connection DeviceContext for node:{}",  connectionContext.getNodeId());
         // Cache this for clarity
         final ConnectionAdapter connectionAdapter = connectionContext.getConnectionAdapter();
@@ -184,8 +167,20 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
         final DeviceState deviceState = new DeviceStateImpl(connectionContext.getFeatures(), nodeId);
 
         final DeviceContext deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker,
-                hashedWheelTimer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary, transactionChainManager);
+                hashedWheelTimer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary);
+
         deviceContext.addDeviceContextClosedHandler(this);
+        // We would like to crete/register TxChainManager after
+        final DeviceTransactionChainManagerProvider.TransactionChainManagerRegistration txChainManagerReg = deviceTransactionChainManagerProvider
+                .provideTransactionChainManager(connectionContext);
+        if (txChainManagerReg.ownedByInvokingConnectionContext()) {
+            //this actually is new registration for currently processed connection context
+            ((DeviceContextImpl) deviceContext).setTransactionChainManager(txChainManagerReg.getTransactionChainManager());
+        } else {
+            LOG.info("In deviceConnected {}, ownedByInvokingConnectionContext is false", connectionContext.getNodeId());
+            deviceContext.close();
+            return;
+        }
         ((ExtensionConverterProviderKeeper) deviceContext).setExtensionConverterProvider(extensionConverterProvider);
         deviceContext.setNotificationService(notificationService);
         deviceContext.setNotificationPublishService(notificationPublishService);
index 06305e1879d4957150b7a19338897e2522f0a5b0..1cfb39bc8eb98661f87e92c5f2bb1443692e562a 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.SettableFuture;
 import java.util.concurrent.Future;
 import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
@@ -41,18 +42,19 @@ import org.slf4j.LoggerFactory;
 public class RoleContextImpl implements RoleContext {
     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
 
-    private EntityOwnershipService entityOwnershipService;
+    private final EntityOwnershipService entityOwnershipService;
     private EntityOwnershipCandidateRegistration entityOwnershipCandidateRegistration;
     private final RpcProviderRegistry rpcProviderRegistry;
-    private DeviceContext deviceContext;
-    private Entity entity;
-    private OpenflowOwnershipListener openflowOwnershipListener;
+    private final DeviceContext deviceContext;
+    private final Entity entity;
+    private final OpenflowOwnershipListener openflowOwnershipListener;
     private SalRoleService salRoleService;
     private FutureCallback<Boolean> roleChangeCallback;
 
+    private final SettableFuture<OfpRole> initRoleChangeFuture;
 
-    public RoleContextImpl(DeviceContext deviceContext, RpcProviderRegistry rpcProviderRegistry,
-                           EntityOwnershipService entityOwnershipService, OpenflowOwnershipListener openflowOwnershipListener) {
+    public RoleContextImpl(final DeviceContext deviceContext, final RpcProviderRegistry rpcProviderRegistry,
+                           final EntityOwnershipService entityOwnershipService, final OpenflowOwnershipListener openflowOwnershipListener) {
         this.entityOwnershipService = entityOwnershipService;
         this.rpcProviderRegistry = rpcProviderRegistry;
         this.deviceContext = deviceContext;
@@ -61,12 +63,21 @@ public class RoleContextImpl implements RoleContext {
         this.openflowOwnershipListener =  openflowOwnershipListener;
         salRoleService = new SalRoleServiceImpl(this, deviceContext);
 
-        //make a call to entity ownership service and listen for notifications from the service
-        requestOpenflowEntityOwnership();
+        initRoleChangeFuture = SettableFuture.create();
     }
 
     @Override
-    public void facilitateRoleChange(FutureCallback<Boolean> roleChangeCallback) {
+    public Future<OfpRole> initialization() throws CandidateAlreadyRegisteredException {
+        LOG.debug("Initialization requestOpenflowEntityOwnership for entity {}", entity);
+        openflowOwnershipListener.registerRoleChangeListener(this);
+        entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
+        LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
+                .getPrimaryConnectionContext().getNodeId().getValue());
+        return initRoleChangeFuture;
+    }
+
+    @Override
+    public void facilitateRoleChange(final FutureCallback<Boolean> roleChangeCallback) {
         this.roleChangeCallback = roleChangeCallback;
         if (!isDeviceConnected()) {
             throw new IllegalStateException(
@@ -83,7 +94,7 @@ public class RoleContextImpl implements RoleContext {
             // The role change listener must be registered after registering a candidate
             openflowOwnershipListener.registerRoleChangeListener(this);
             LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext.getPrimaryConnectionContext().getNodeId().getValue());
-        } catch (CandidateAlreadyRegisteredException e) {
+        } catch (final CandidateAlreadyRegisteredException e) {
             // we can log and move for this error, as listener is present and role changes will be served.
             LOG.error("Candidate - Entity already registered with Openflow candidate ", entity, e );
         }
@@ -91,14 +102,24 @@ public class RoleContextImpl implements RoleContext {
 
     @Override
     public void onRoleChanged(final OfpRole oldRole, final OfpRole newRole) {
+        LOG.trace("onRoleChanged method call for Entity {}", entity);
 
         if (!isDeviceConnected()) {
             // this can happen as after the disconnect, we still get a last messsage from EntityOwnershipService.
             LOG.info("Device {} is disconnected from this node. Hence not attempting a role change.",
                     deviceContext.getPrimaryConnectionContext().getNodeId());
+            if (!initRoleChangeFuture.isDone()) {
+                LOG.debug("RoleChange is not valid for initialization Entity {} anymore - Device is disconnected", entity);
+                initRoleChangeFuture.cancel(true);
+            }
             return;
         }
 
+        if (!initRoleChangeFuture.isDone()) {
+            LOG.debug("Initialization Role for entity {} is chosed {}", entity, newRole);
+            initRoleChangeFuture.set(newRole);
+        }
+
         LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
                 deviceContext.getPrimaryConnectionContext().getNodeId());
 
@@ -107,11 +128,11 @@ public class RoleContextImpl implements RoleContext {
                 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier()))
                 .build();
 
-        Future<RpcResult<SetRoleOutput>> setRoleOutputFuture = salRoleService.setRole(setRoleInput);
+        final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture = salRoleService.setRole(setRoleInput);
 
         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), new FutureCallback<RpcResult<SetRoleOutput>>() {
             @Override
-            public void onSuccess(RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+            public void onSuccess(final RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
                 LOG.debug("Rolechange {} successful made on switch :{}", newRole,
                         deviceContext.getPrimaryConnectionContext().getNodeId());
                 deviceContext.getDeviceState().setRole(newRole);
@@ -121,7 +142,7 @@ public class RoleContextImpl implements RoleContext {
             }
 
             @Override
-            public void onFailure(Throwable throwable) {
+            public void onFailure(final Throwable throwable) {
                 LOG.error("Error in setRole {} for device {} ", newRole,
                         deviceContext.getPrimaryConnectionContext().getNodeId(), throwable);
                 if (roleChangeCallback != null) {
@@ -140,11 +161,11 @@ public class RoleContextImpl implements RoleContext {
     }
 
     @Override
-    public void onDeviceContextClosed(DeviceContext deviceContext) {
+    public void onDeviceContextClosed(final DeviceContext deviceContext) {
         try {
             LOG.debug("onDeviceContextClosed called");
             this.close();
-        } catch (Exception e) {
+        } catch (final Exception e) {
             LOG.error("Exception in onDeviceContextClosed of RoleContext", e);
         }
     }
@@ -177,7 +198,7 @@ public class RoleContextImpl implements RoleContext {
     }
 
     @VisibleForTesting
-    public void setSalRoleService(SalRoleService salRoleService) {
+    public void setSalRoleService(final SalRoleService salRoleService) {
         this.salRoleService = salRoleService;
     }
 }
index 78cb8c7e6f630673c690f7cd56f9a631a4e54537..0dbbd63a49aceb1389bc1d707c90e79fd8b9234a 100644 (file)
@@ -7,17 +7,29 @@
  */
 package org.opendaylight.openflowplugin.impl.role;
 
-import com.google.common.util.concurrent.FutureCallback;
+import javax.annotation.CheckForNull;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import javax.annotation.CheckForNull;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
+import org.opendaylight.openflowplugin.impl.util.DeviceInitializationUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,21 +43,24 @@ public class RoleManagerImpl implements RoleManager {
     private static final Logger LOG = LoggerFactory.getLogger(RoleManagerImpl.class);
 
     private DeviceInitializationPhaseHandler deviceInitializationPhaseHandler;
-    private EntityOwnershipService entityOwnershipService;
+    private final EntityOwnershipService entityOwnershipService;
     private final RpcProviderRegistry rpcProviderRegistry;
     private final ConcurrentHashMap<DeviceContext, RoleContext> contexts = new ConcurrentHashMap<>();
     private final OpenflowOwnershipListener openflowOwnershipListener;
+    private final boolean switchFeaturesMandatory;
 
-    public RoleManagerImpl(RpcProviderRegistry rpcProviderRegistry, EntityOwnershipService entityOwnershipService) {
-        this.entityOwnershipService = entityOwnershipService;
-        this.rpcProviderRegistry = rpcProviderRegistry;
+    public RoleManagerImpl(final RpcProviderRegistry rpcProviderRegistry,
+            final EntityOwnershipService entityOwnershipService, final boolean switchFeaturesMandatory) {
+        this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
+        this.rpcProviderRegistry = Preconditions.checkNotNull(rpcProviderRegistry);
+        this.switchFeaturesMandatory = switchFeaturesMandatory;
         this.openflowOwnershipListener = new OpenflowOwnershipListener(entityOwnershipService);
         LOG.debug("Registering OpenflowOwnershipListener listening to all entity ownership changes");
         openflowOwnershipListener.init();
     }
 
     @Override
-    public void setDeviceInitializationPhaseHandler(DeviceInitializationPhaseHandler handler) {
+    public void setDeviceInitializationPhaseHandler(final DeviceInitializationPhaseHandler handler) {
         deviceInitializationPhaseHandler = handler;
     }
 
@@ -58,39 +73,64 @@ public class RoleManagerImpl implements RoleManager {
             return;
         }
 
-        RoleContext roleContext = new RoleContextImpl(deviceContext, rpcProviderRegistry, entityOwnershipService, openflowOwnershipListener);
+        final RoleContext roleContext = new RoleContextImpl(deviceContext, rpcProviderRegistry, entityOwnershipService, openflowOwnershipListener);
         contexts.put(deviceContext, roleContext);
-        LOG.debug("Created role context");
-
         // if the device context gets closed (mostly on connection close), we would need to cleanup
         deviceContext.addDeviceContextClosedHandler(roleContext);
-
-        roleContext.facilitateRoleChange(new FutureCallback<Boolean>() {
-            @Override
-            public void onSuccess(Boolean aBoolean) {
-                LOG.debug("roleChangeFuture success for device:{}. Moving to StatisticsManager", deviceContext.getDeviceState().getNodeId());
-                deviceInitializationPhaseHandler.onDeviceContextLevelUp(deviceContext);
-            }
-
-            @Override
-            public void onFailure(Throwable throwable) {
-                LOG.error("RoleChange on device {} was not successful after several attempts. " +
-                        "Closing the device Context, reconnect the device and start over",
-                        deviceContext.getPrimaryConnectionContext().getNodeId().getValue(), throwable);
+        OfpRole role = null;
+        try {
+            role = roleContext.initialization().get(5, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException | CandidateAlreadyRegisteredException e) {
+            LOG.warn("Unexpected exception by DeviceConection {}. Connection has to close.", deviceContext.getDeviceState().getNodeId(), e);
+            final Optional<EntityOwnershipState> entityOwnershipStateOptional = entityOwnershipService.getOwnershipState(roleContext.getEntity());
+            if (entityOwnershipStateOptional.isPresent()) {
+                role = entityOwnershipStateOptional.get().isOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
+            } else {
                 try {
                     deviceContext.close();
-                } catch (Exception e) {
-                    LOG.warn("Error closing device context for device:{}",
-                            deviceContext.getPrimaryConnectionContext().getNodeId().getValue(),  e);
+                } catch (Exception e1) {
+                    LOG.warn("Exception during device context close. ", e);
                 }
+                return;
             }
-        });
+        }
+        if (OfpRole.BECOMEMASTER.equals(role)) {
+            final ListenableFuture<Void> initNodeFuture = DeviceInitializationUtils.initializeNodeInformation(deviceContext, switchFeaturesMandatory);
+            Futures.addCallback(initNodeFuture, new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(final Void result) {
+                    LOG.trace("Node {} was initialized", deviceContext.getDeviceState().getNodeId());
+                    getRoleContextLevelUp(deviceContext);
+                }
+
+                @Override
+                public void onFailure(final Throwable t) {
+                    LOG.warn("Node {} Initialization fail", deviceContext.getDeviceState().getNodeId(), t);
+                    try {
+                        deviceContext.close();
+                    } catch (Exception e) {
+                        LOG.warn("Exception during device context close. ", e);
+                    }
+                }
+            });
+        } else {
+            getRoleContextLevelUp(deviceContext);
+        }
+
+    }
+
+    void getRoleContextLevelUp(final DeviceContext deviceContext) {
+        LOG.debug("Created role context for node {}", deviceContext.getDeviceState().getNodeId());
+        LOG.debug("roleChangeFuture success for device:{}. Moving to StatisticsManager", deviceContext.getDeviceState().getNodeId());
+        deviceInitializationPhaseHandler.onDeviceContextLevelUp(deviceContext);
     }
 
     @Override
     public void close() throws Exception {
-        for (Map.Entry<DeviceContext, RoleContext> roleContextEntry : contexts.entrySet()) {
-            roleContextEntry.getValue().close();
+        for (final Map.Entry<DeviceContext, RoleContext> roleContextEntry : contexts.entrySet()) {
+            if (roleContextEntry.getValue() != null) {
+                roleContextEntry.getValue().close();
+            }
         }
         this.openflowOwnershipListener.close();
     }
index 784ea0a4603f1a376da842ad20a4bb96108931a7..09310a4e397f6dddf630c1626f7182fac10c65f0 100644 (file)
@@ -98,7 +98,7 @@ public class DeviceInitializationUtils {
      * @param switchFeaturesMandatory
      * @return future - recommended to have blocking call for this future
      */
-    public static Future<Void> initializeNodeInformation(final DeviceContext deviceContext, final boolean switchFeaturesMandatory) {
+    public static ListenableFuture<Void> initializeNodeInformation(final DeviceContext deviceContext, final boolean switchFeaturesMandatory) {
         Preconditions.checkArgument(deviceContext != null);
         final DeviceState deviceState = Preconditions.checkNotNull(deviceContext.getDeviceState());
         final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
@@ -165,7 +165,7 @@ public class DeviceInitializationUtils {
                 LOG.trace("Device capabilities gathering future failed.");
                 LOG.trace("more info in exploration failure..", t);
                 LOG.debug("All init data for node {} was not submited correctly - connection has to go down.", deviceState.getNodeId());
-                returnFuture.cancel(true);
+                returnFuture.setException(t);
             }
         });
         return returnFuture;
index 34ee686fd872201c267b2a2319c7e7a6daac3710..71d16b6c88b6d472cbf44ec747b141bb0b53ac5c 100644 (file)
@@ -16,6 +16,10 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.math.BigInteger;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicLong;
+
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.CheckedFuture;
@@ -102,9 +106,6 @@ import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
-import java.net.InetSocketAddress;
-import java.util.concurrent.atomic.AtomicLong;
 
 @RunWith(MockitoJUnitRunner.class)
 public class DeviceContextImplTest {
@@ -205,7 +206,8 @@ public class DeviceContextImplTest {
                 org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemoved.class.getName()))))
                 .thenReturn(messageTranslatorFlowRemoved);
 
-        deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary, txChainManager);
+        deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary);
+        deviceContext.setTransactionChainManager(txChainManager);
 
         xid = new Xid(atomicLong.incrementAndGet());
         xidMulti = new Xid(atomicLong.incrementAndGet());
@@ -213,17 +215,17 @@ public class DeviceContextImplTest {
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullDataBroker() throws Exception {
-        new DeviceContextImpl(connectionContext, deviceState, null, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary, txChainManager).close();
+        new DeviceContextImpl(connectionContext, deviceState, null, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary).close();
     }
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullDeviceState() throws Exception {
-        new DeviceContextImpl(connectionContext, null, dataBroker, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary, txChainManager).close();
+        new DeviceContextImpl(connectionContext, null, dataBroker, timer, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary).close();
     }
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullTimer() throws Exception {
-        new DeviceContextImpl(null, deviceState, dataBroker, null, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary, txChainManager).close();
+        new DeviceContextImpl(null, deviceState, dataBroker, null, messageIntelligenceAgency, outboundQueueProvider, translatorLibrary).close();
     }
 
     @Test