X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openflowplugin-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fimpl%2FOpenFlowPluginProviderImpl.java;h=034245b55e336149c30b7499b886ce355c9bc34c;hb=HEAD;hp=541ba88b529c7a59f905258edf5dac16b84b5f94;hpb=5ab92c0df913f194d6910377ef72b7e6953a7922;p=openflowplugin.git diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java index 541ba88b52..9e81231ce7 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java @@ -5,353 +5,373 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.openflowplugin.impl; +import static java.util.Objects.requireNonNull; -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 com.google.common.util.concurrent.MoreExecutors; import io.netty.util.HashedWheelTimer; -import java.lang.management.ManagementFactory; +import io.netty.util.Timer; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -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; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.opendaylight.infrautils.diagstatus.ServiceState; +import org.opendaylight.infrautils.ready.SystemReadyListener; +import org.opendaylight.infrautils.ready.SystemReadyMonitor; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.NotificationPublishService; +import org.opendaylight.mdsal.binding.api.RpcProviderService; +import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService; +import org.opendaylight.mdsal.singleton.api.ClusterSingletonServiceProvider; import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider; -import org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider; +import org.opendaylight.openflowplugin.api.openflow.FlowGroupInfoHistories; +import org.opendaylight.openflowplugin.api.openflow.FlowGroupInfoHistory; +import org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationService; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager; import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager; +import org.opendaylight.openflowplugin.api.openflow.role.RoleManager; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager; import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager; import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency; -import org.opendaylight.openflowplugin.extension.api.ExtensionConverterProviderKeeper; import org.opendaylight.openflowplugin.extension.api.ExtensionConverterRegistrator; import org.opendaylight.openflowplugin.extension.api.OpenFlowPluginExtensionRegistratorProvider; import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterManager; +import org.opendaylight.openflowplugin.impl.configuration.OpenFlowProviderConfigImpl; import org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl; import org.opendaylight.openflowplugin.impl.device.DeviceManagerImpl; +import org.opendaylight.openflowplugin.impl.device.initialization.DeviceInitializerProvider; +import org.opendaylight.openflowplugin.impl.device.initialization.DeviceInitializerProviderFactory; +import org.opendaylight.openflowplugin.impl.lifecycle.ContextChainHolderImpl; +import org.opendaylight.openflowplugin.impl.protocol.deserialization.DeserializerInjector; +import org.opendaylight.openflowplugin.impl.protocol.serialization.SerializerInjector; +import org.opendaylight.openflowplugin.impl.role.RoleManagerImpl; import org.opendaylight.openflowplugin.impl.rpc.RpcManagerImpl; import org.opendaylight.openflowplugin.impl.statistics.StatisticsManagerImpl; -import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyImpl; -import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyMXBean; +import org.opendaylight.openflowplugin.impl.util.ThreadPoolLoggingExecutor; import org.opendaylight.openflowplugin.impl.util.TranslatorLibraryUtil; -import org.opendaylight.openflowplugin.openflow.md.core.ThreadPoolLoggingExecutor; import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManagerImpl; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManager; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManagerFactory; import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenFlowPluginExtensionRegistratorProvider { - +@Singleton +@Component(immediate = true, service = { + OpenFlowPluginExtensionRegistratorProvider.class, + FlowGroupInfoHistories.class +}) +public final class OpenFlowPluginProviderImpl + implements OpenFlowPluginExtensionRegistratorProvider, FlowGroupInfoHistories, SystemReadyListener, + AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(OpenFlowPluginProviderImpl.class); - private static final MessageIntelligenceAgency messageIntelligenceAgency = new MessageIntelligenceAgencyImpl(); - private static final int TICKS_PER_WHEEL = 500; - // 0.5 sec. - private static final long TICK_DURATION = 10; - private static final Integer DEFAULT_BARRIER_COUNT = 25600; - private static final Long DEFAULT_ECHO_TIMEOUT = 2000L; - private static final Long DEFAULT_BARRIER_TIMEOUT = 500L; - - private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(TICK_DURATION, TimeUnit.MILLISECONDS, TICKS_PER_WHEEL); - private final int rpcRequestsQuota; - private final long globalNotificationQuota; + private static final int TICKS_PER_WHEEL = 500; // 0.5 sec. + private static final long TICK_DURATION = 10; + private static final String POOL_NAME = "ofppool"; + + // TODO: Split this out into a separate component, which requires proper timer cancellation from all users. But is + // that worth the complications? + private final HashedWheelTimer hashedWheelTimer = + new HashedWheelTimer(TICK_DURATION, TimeUnit.MILLISECONDS, TICKS_PER_WHEEL); + private final ExtensionConverterManager extensionConverterManager; + private final DeviceInitializerProvider deviceInitializerProvider; private final ConvertorManager convertorManager; - private long barrierInterval; - private int barrierCountLimit; - private long echoReplyTimeout; - private DeviceManager deviceManager; - private RpcManager rpcManager; - private RpcProviderRegistry rpcProviderRegistry; - private StatisticsManager statisticsManager; + private final OpenflowProviderConfig config; + private final DeviceManager deviceManager; + private final RpcManager rpcManager; + private final StatisticsManager statisticsManager; + private final RoleManager roleManager; + private final ExecutorService executorService; + private final ContextChainHolderImpl contextChainHolder; + private final DiagStatusProvider diagStatusProvider; + + private final List connectionProviders = new ArrayList<>(); + + private List startedProviders; private ConnectionManager connectionManager; - private NotificationService notificationProviderService; - private NotificationPublishService notificationPublishService; - private ExtensionConverterManager extensionConverterManager; - private DataBroker dataBroker; - private Collection switchConnectionProviders; - private boolean switchFeaturesMandatory = false; - private boolean isStatisticsPollingOn = true; - private boolean isStatisticsRpcEnabled; - private boolean isNotificationFlowRemovedOff = false; - private boolean skipTableFeatures = true; - - private final ThreadPoolExecutor threadPool; - private ClusterSingletonServiceProvider singletonServicesProvider; - - public OpenFlowPluginProviderImpl(final long rpcRequestsQuota, - final long globalNotificationQuota, - final int threadPoolMinThreads, - final int threadPoolMaxThreads, - final long threadPoolTimeout) { - Preconditions.checkArgument(rpcRequestsQuota > 0 && rpcRequestsQuota <= Integer.MAX_VALUE, "rpcRequestQuota has to be in range <1,%s>", Integer.MAX_VALUE); - this.rpcRequestsQuota = (int) rpcRequestsQuota; - this.globalNotificationQuota = Preconditions.checkNotNull(globalNotificationQuota); + private int startingProviders; + + @Inject + @Activate + public OpenFlowPluginProviderImpl(@Reference final ConfigurationService configurationService, + @Reference final DataBroker dataBroker, @Reference final RpcProviderService rpcProviderRegistry, + @Reference final NotificationPublishService notificationPublishService, + @Reference final ClusterSingletonServiceProvider singletonServiceProvider, + @Reference final EntityOwnershipService entityOwnershipService, + @Reference final MastershipChangeServiceManager mastershipChangeServiceManager, + @Reference final MessageIntelligenceAgency messageIntelligenceAgency, + @Reference final DiagStatusProvider diagStatusProvider, + @Reference final SystemReadyMonitor systemReadyMonitor) { + config = new OpenFlowProviderConfigImpl(configurationService); + final var ppdb = new PingPongDataBroker(dataBroker); + this.diagStatusProvider = requireNonNull(diagStatusProvider); + + convertorManager = ConvertorManagerFactory.createDefaultManager(); + extensionConverterManager = new ExtensionConverterManagerImpl(); + deviceInitializerProvider = DeviceInitializerProviderFactory.createDefaultProvider(); + + // TODO: copied from OpenFlowPluginProvider (Helium) misusesing the old way of distributing extension converters + // TODO: rewrite later! + OFSessionUtil.getSessionManager().setExtensionConverterProvider(extensionConverterManager); // Creates a thread pool that creates new threads as needed, but will reuse previously // constructed threads when they are available. // Threads that have not been used for x seconds are terminated and removed from the cache. - threadPool = new ThreadPoolLoggingExecutor( - Preconditions.checkNotNull(threadPoolMinThreads), - Preconditions.checkNotNull(threadPoolMaxThreads), - Preconditions.checkNotNull(threadPoolTimeout), TimeUnit.SECONDS, - new SynchronousQueue<>(), "ofppool"); - convertorManager = ConvertorManagerFactory.createDefaultManager(); + executorService = new ThreadPoolLoggingExecutor( + config.getThreadPoolMinThreads().toJava(), + config.getThreadPoolMaxThreads().getValue().toJava(), + config.getThreadPoolTimeout().toJava(), + TimeUnit.SECONDS, new SynchronousQueue<>(), POOL_NAME); + + final var devMgr = new DeviceManagerImpl( + config, + ppdb, + messageIntelligenceAgency, + notificationPublishService, + hashedWheelTimer, + convertorManager, + deviceInitializerProvider, + executorService); + deviceManager = devMgr; + + TranslatorLibraryUtil.injectBasicTranslatorLibrary(deviceManager, convertorManager); + devMgr.setExtensionConverterProvider(extensionConverterManager); + + rpcManager = new RpcManagerImpl( + config, + rpcProviderRegistry, + extensionConverterManager, + convertorManager, + notificationPublishService); + + statisticsManager = new StatisticsManagerImpl( + config, + rpcProviderRegistry, + convertorManager, + executorService); + + roleManager = new RoleManagerImpl(hashedWheelTimer, config, executorService); + + contextChainHolder = new ContextChainHolderImpl( + executorService, + singletonServiceProvider, + entityOwnershipService, + mastershipChangeServiceManager, + config); + + contextChainHolder.addManager(deviceManager); + contextChainHolder.addManager(statisticsManager); + contextChainHolder.addManager(rpcManager); + contextChainHolder.addManager(roleManager); + + connectionManager = new ConnectionManagerImpl(config, executorService, ppdb, notificationPublishService); + connectionManager.setDeviceConnectedHandler(contextChainHolder); + connectionManager.setDeviceDisconnectedHandler(contextChainHolder); + + deviceManager.setContextChainHolder(contextChainHolder); + deviceManager.initialize(); + systemReadyMonitor.registerListener(this); + LOG.info("OpenFlowPluginProvider started, waiting for onSystemBootReady()"); } - @Override - public boolean isStatisticsPollingOn() { - return isStatisticsPollingOn; + @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, + policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) + public synchronized void bindConnectionProvider(final SwitchConnectionProvider switchConnectionProvider) { + connectionProviders.add(switchConnectionProvider); + LOG.info("Added connection provider {}", switchConnectionProvider); + + if (startedProviders != null) { + LOG.info("Starting latecomer connection provider {}", switchConnectionProvider); + startingProviders += 1; + startProvider(switchConnectionProvider); + } } - @Override - public void setIsStatisticsPollingOn(final boolean isStatisticsPollingOn) { - this.isStatisticsPollingOn = isStatisticsPollingOn; + public synchronized void unbindConnectionProvider(final SwitchConnectionProvider switchConnectionProvider) { + connectionProviders.remove(switchConnectionProvider); + if (startedProviders != null && startedProviders.remove(switchConnectionProvider)) { + switchConnectionProvider.shutdown(); + } + LOG.info("Removed connection provider {}", switchConnectionProvider); } - private void startSwitchConnections() { - final List> starterChain = new ArrayList<>(switchConnectionProviders.size()); - for (final SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) { - switchConnectionPrv.setSwitchConnectionHandler(connectionManager); - final ListenableFuture isOnlineFuture = switchConnectionPrv.startup(); - starterChain.add(isOnlineFuture); + private ListenableFuture startProvider(final SwitchConnectionProvider provider) { + // Inject OpenFlowPlugin custom serializers and deserializers into OpenFlowJava + if (config.getUseSingleLayerSerialization()) { + SerializerInjector.injectSerializers(provider, provider.getConfiguration().isGroupAddModEnabled()); + DeserializerInjector.injectDeserializers(provider); + } else { + DeserializerInjector.revertDeserializers(provider); } - final ListenableFuture> srvStarted = Futures.allAsList(starterChain); - Futures.addCallback(srvStarted, new FutureCallback>() { + // Set handler of incoming connections and start switch connection provider + final var future = provider.startup(connectionManager); + startedProviders.add(provider); + Futures.addCallback(future, new FutureCallback<>() { @Override - public void onSuccess(final List result) { - LOG.info("All switchConnectionProviders are up and running ({}).", - result.size()); + public void onSuccess(final Void result) { + LOG.info("Connection provider {} started", provider); + connectionStarted(); } @Override - public void onFailure(@Nonnull final Throwable t) { - LOG.warn("Some switchConnectionProviders failed to start.", t); + public void onFailure(final Throwable cause) { + LOG.warn("Connection provider {} failed to start", provider, cause); + connectionFailed(cause); } - }); - } - - @Override - public boolean isSwitchFeaturesMandatory() { - return switchFeaturesMandatory; + }, MoreExecutors.directExecutor()); + return future; } @Override - public void setBarrierCountLimit(final int barrierCountLimit) { - this.barrierCountLimit = barrierCountLimit; - } + public synchronized void onSystemBootReady() { + LOG.info("onSystemBootReady() received, starting the switch connections"); - @Override - public void setBarrierInterval(final long barrierTimeoutLimit) { - this.barrierInterval = barrierTimeoutLimit; + final var size = connectionProviders.size(); + startedProviders = new ArrayList<>(size); + startingProviders = size; + connectionProviders.forEach(this::startProvider); } - @Override - public void setEchoReplyTimeout(final long echoReplyTimeout) { - this.echoReplyTimeout = echoReplyTimeout; + private synchronized void connectionFailed(final Throwable cause) { + // Decrement below zero, so we do not arrive to zero + startingProviders = -1; + diagStatusProvider.reportStatus(ServiceState.ERROR, cause); } - @Override - public void setNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) { - this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff; + private synchronized void connectionStarted() { + if (--startingProviders == 0 && startedProviders.equals(connectionProviders)) { + LOG.info("All switchConnectionProviders are up and running ({}).", startedProviders.size()); + diagStatusProvider.reportStatus(ServiceState.OPERATIONAL); + } } - @Override - public void setClusteringSingletonServicesProvider(ClusterSingletonServiceProvider singletonServicesProvider) { - this.singletonServicesProvider = singletonServicesProvider; - } + private ListenableFuture> shutdownSwitchConnections() { + final var future = Futures.allAsList(startedProviders.stream() + .map(switchConnectionProvider -> { + // Revert deserializers to their original state + if (config.getUseSingleLayerSerialization()) { + DeserializerInjector.revertDeserializers(switchConnectionProvider); + } - @Override - public void setSkipTableFeatures(final boolean skipTableFeatures){ - this.skipTableFeatures = skipTableFeatures; - } + // Shutdown switch connection provider + return switchConnectionProvider.shutdown(); + }).collect(Collectors.toList())); + startedProviders.clear(); - @Override - public void setSwitchFeaturesMandatory(final boolean switchFeaturesMandatory) { - this.switchFeaturesMandatory = switchFeaturesMandatory; - } + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(final List result) { + LOG.info("All switchConnectionProviders were successfully shut down ({}).", result.size()); + } - public static MessageIntelligenceAgency getMessageIntelligenceAgency() { - return OpenFlowPluginProviderImpl.messageIntelligenceAgency; - } + @Override + public void onFailure(final Throwable throwable) { + LOG.warn("Some switchConnectionProviders failed to shutdown.", throwable); + } + }, MoreExecutors.directExecutor()); - @Override - public void setSwitchConnectionProviders(final Collection switchConnectionProviders) { - this.switchConnectionProviders = switchConnectionProviders; + return future; } @Override - public void setDataBroker(final DataBroker dataBroker) { - this.dataBroker = dataBroker; + public ExtensionConverterRegistrator getExtensionConverterRegistrator() { + return extensionConverterManager; } @Override - public void setRpcProviderRegistry(final RpcProviderRegistry rpcProviderRegistry) { - this.rpcProviderRegistry = rpcProviderRegistry; + public Map getAllFlowGroupHistories() { + return deviceManager.getAllFlowGroupHistories(); } @Override - public void initialize() { - Preconditions.checkNotNull(dataBroker, "missing data broker"); - Preconditions.checkNotNull(rpcProviderRegistry, "missing RPC provider registry"); - Preconditions.checkNotNull(notificationProviderService, "missing notification provider service"); - Preconditions.checkNotNull(singletonServicesProvider, "missing singleton services provider"); - - extensionConverterManager = new ExtensionConverterManagerImpl(); - // TODO: copied from OpenFlowPluginProvider (Helium) misusesing the old way of distributing extension converters - // TODO: rewrite later! - OFSessionUtil.getSessionManager().setExtensionConverterProvider(extensionConverterManager); - - connectionManager = new ConnectionManagerImpl(echoReplyTimeout, threadPool); - - registerMXBean(messageIntelligenceAgency); - - deviceManager = new DeviceManagerImpl(dataBroker, - globalNotificationQuota, - switchFeaturesMandatory, - barrierInterval, - barrierCountLimit, - getMessageIntelligenceAgency(), - isNotificationFlowRemovedOff, - singletonServicesProvider, - notificationPublishService, - hashedWheelTimer, - convertorManager, - skipTableFeatures); - - ((ExtensionConverterProviderKeeper) deviceManager).setExtensionConverterProvider(extensionConverterManager); - - rpcManager = new RpcManagerImpl(rpcProviderRegistry, rpcRequestsQuota, extensionConverterManager, convertorManager, notificationPublishService); - statisticsManager = new StatisticsManagerImpl(rpcProviderRegistry, isStatisticsPollingOn, hashedWheelTimer, convertorManager); - - /* Initialization Phase ordering - OFP Device Context suite */ - // CM -> DM -> SM -> RPC -> Role -> DM - connectionManager.setDeviceConnectedHandler(deviceManager); - deviceManager.setDeviceInitializationPhaseHandler(statisticsManager); - statisticsManager.setDeviceInitializationPhaseHandler(rpcManager); - rpcManager.setDeviceInitializationPhaseHandler(deviceManager); - - /* Termination Phase ordering - OFP Device Context suite */ - deviceManager.setDeviceTerminationPhaseHandler(rpcManager); - rpcManager.setDeviceTerminationPhaseHandler(statisticsManager); - statisticsManager.setDeviceTerminationPhaseHandler(deviceManager); - - rpcManager.setStatisticsRpcEnabled(isStatisticsRpcEnabled); - - TranslatorLibraryUtil.injectBasicTranslatorLibrary(deviceManager, convertorManager); - deviceManager.initialize(); - - startSwitchConnections(); + public FlowGroupInfoHistory getFlowGroupHistory(final NodeId nodeId) { + return deviceManager.getFlowGroupHistory(nodeId); } @Override - public void update(Map props) { - LOG.debug("Update managed properties = {}", props.toString()); - - if(deviceManager != null) { - if (props.containsKey("notification-flow-removed-off")) { - deviceManager.setIsNotificationFlowRemovedOff(Boolean.valueOf(props.get("notification-flow-removed-off").toString())); - } - if (props.containsKey("skip-table-features")) { - deviceManager.setSkipTableFeatures(Boolean.valueOf(props.get("skip-table-features").toString())); - } - if (props.containsKey("barrier-count-limit")) { - try { - deviceManager.setBarrierCountLimit(Integer.valueOf(props.get("barrier-count-limit").toString())); - } catch (NumberFormatException ex) { - deviceManager.setBarrierCountLimit(DEFAULT_BARRIER_COUNT); - } - } - if (props.containsKey("barrier-interval-timeout-limit")){ - try { - deviceManager.setBarrierInterval(Long.valueOf(props.get("barrier-interval-timeout-limit").toString())); - } catch (NumberFormatException ex) { - deviceManager.setBarrierInterval(DEFAULT_BARRIER_TIMEOUT); - } - } + @PreDestroy + @Deactivate + @SuppressWarnings("checkstyle:IllegalCatch") + public synchronized void close() { + LOG.info("OpenFlowPluginProvider stopping"); + try { + shutdownSwitchConnections().get(10, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.warn("Failed to shut down switch connections in time {}s", 10, e); } - if(rpcManager != null && props.containsKey("is-statistics-rpc-enabled")){ - rpcManager.setStatisticsRpcEnabled(Boolean.valueOf((props.get("is-statistics-rpc-enabled").toString()))); + gracefulShutdown(contextChainHolder); + gracefulShutdown(connectionManager); + gracefulShutdown(deviceManager); + gracefulShutdown(rpcManager); + gracefulShutdown(statisticsManager); + gracefulShutdown(roleManager); + gracefulShutdown(executorService); + gracefulShutdown(hashedWheelTimer); + diagStatusProvider.reportStatus(ServiceState.UNREGISTERED); + try { + if (connectionManager != null) { + connectionManager.close(); + connectionManager = null; + } + } catch (Exception e) { + LOG.error("Failed to close ConnectionManager", e); } + LOG.info("OpenFlowPluginProvider stopped"); + } - if (connectionManager != null && props.containsKey("echo-reply-timeout") ){ + @SuppressWarnings("checkstyle:IllegalCatch") + private static void gracefulShutdown(final AutoCloseable closeable) { + if (closeable != null) { try { - connectionManager.setEchoReplyTimeout(Long.valueOf(props.get("echo-reply-timeout").toString())); - }catch (NumberFormatException ex){ - connectionManager.setEchoReplyTimeout(DEFAULT_ECHO_TIMEOUT); + closeable.close(); + } catch (Exception e) { + LOG.warn("Failed to shutdown {} gracefully.", closeable); } } - - if(statisticsManager != null && props.containsKey("is-statistics-polling-on")){ - statisticsManager.setIsStatisticsPollingOn(Boolean.valueOf(props.get("is-statistics-polling-on").toString())); - } } - private static void registerMXBean(final MessageIntelligenceAgency messageIntelligenceAgency) { - final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - try { - final String pathToMxBean = String.format("%s:type=%s", - MessageIntelligenceAgencyMXBean.class.getPackage().getName(), - MessageIntelligenceAgencyMXBean.class.getSimpleName()); - final ObjectName name = new ObjectName(pathToMxBean); - mbs.registerMBean(messageIntelligenceAgency, name); - } catch (MalformedObjectNameException - | NotCompliantMBeanException - | MBeanRegistrationException - | InstanceAlreadyExistsException e) { - LOG.warn("Error registering MBean {}", e); + private static void gracefulShutdown(final Timer timer) { + if (timer != null) { + try { + timer.stop(); + } catch (IllegalStateException e) { + LOG.warn("Failed to shutdown {} gracefully.", timer); + } } } - @Override - public void setNotificationProviderService(final NotificationService notificationProviderService) { - this.notificationProviderService = notificationProviderService; - } - - @Override - public void setNotificationPublishService(final NotificationPublishService notificationPublishProviderService) { - this.notificationPublishService = notificationPublishProviderService; - } - - @Override - public ExtensionConverterRegistrator getExtensionConverterRegistrator() { - return extensionConverterManager; - } - - @Override - public void setIsStatisticsRpcEnabled(final boolean isStatisticsRpcEnabled) { - this.isStatisticsRpcEnabled = isStatisticsRpcEnabled; - } - - @Override - public void close() throws Exception { - //TODO: consider wrapping each manager into try-catch - deviceManager.close(); - rpcManager.close(); - statisticsManager.close(); - - // Manually shutdown all remaining running threads in pool - threadPool.shutdown(); + private static void gracefulShutdown(final ExecutorService executorService) { + if (executorService != null) { + try { + executorService.shutdownNow(); + } catch (SecurityException e) { + LOG.warn("Failed to shutdown {} gracefully.", executorService); + } + } } -} \ No newline at end of file +}