--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.api.openflow.mastership;
+
+public class MastershipChangeException extends Exception {
+
+ private static final long serialVersionUID = 998L;
+
+ public MastershipChangeException(String message) {
+ super(message);
+ }
+
+ public MastershipChangeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
* <li><i>onLoseOwnership</i>
* </ul>
* @see MastershipChangeService
- * @see ReconciliationFrameworkEvent
* @since 0.5.0 Nitrogen
*/
public interface MastershipChangeRegistration extends AutoCloseable {
* It doesn't contain event for reconciliation framework event.
* @param service implementation of {@link MastershipChangeService}
* @return registration
- * @since 0.5.0 Nitrogen
* @see ReconciliationFrameworkEvent
*/
@Nonnull
/**
* Setter for reconciliation framework event listener. It can be registered only once.
- * Another registrations will be ignored.
- * @see ReconciliationFrameworkEvent
- * @since 0.5.0 Nitrogen
+ * Another registrations will throw an exception
* @param mastershipRFRegistration reconciliation framework
+ * @return registration object, which can be closed to unregister
+ * @throws MastershipChangeException if already reconciliation framework registered
*/
- void reconciliationFrameworkRegistration(@Nonnull ReconciliationFrameworkEvent mastershipRFRegistration);
-
- /**
- * Unregister of listener. Registration after unregister need to be closed by client.
- * @param service implementation of {@link MastershipChangeService}
- * @since 0.5.0 Nitrogen
- */
- void unregister(@Nonnull MastershipChangeService service);
+ ReconciliationFrameworkRegistration reconciliationFrameworkRegistration(
+ @Nonnull ReconciliationFrameworkEvent mastershipRFRegistration) throws MastershipChangeException;
@Override
void close();
+++ /dev/null
-/*
- * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * 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.api.openflow.mastership;
-
-/**
- * Factory for mastership change service manager.
- * @see MastershipChangeServiceManager
- * @see MastershipChangeService
- * @since 0.5.0 Nitrogen
- */
-public interface MastershipChangeServiceManagerFactory {
-
- /**
- * Creates instance of mastership change service manager.
- * @return new instance
- */
- MastershipChangeServiceManager newInstance();
-
-}
import com.google.common.util.concurrent.FutureCallback;
import javax.annotation.Nonnull;
-import org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationProperty;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.OwnershipChangeListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
* @param deviceInfo connected switch identification
* @param callback callback need to be attached to reconciliation result future
*/
- default void onDevicePrepared(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback<ResultState> callback) {
- callback.onSuccess(ResultState.DONOTHING);
- }
+ void onDevicePrepared(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback<ResultState> callback);
+
+ /**
+ * This event occurs after device is disconnected or being slaved.
+ * Event is similar to the {@link MastershipChangeService#onLoseOwnership(DeviceInfo)}. This event is used by
+ * reconciliation framework that the framework don't need to register {@link MastershipChangeService}
+ * @param deviceInfo connected switch identification
+ * @see MastershipChangeService
+ */
+ void onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo);
+
+
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.api.openflow.mastership;
+
+/**
+ * API provided for reconciliation framework registration.
+ * Service provides three events.
+ * <ul>
+ * <li><i>onDevicePrepared</i>
+ * <li><i>onDeviceDisconnected</i>
+ * </ul>
+ * @see ReconciliationFrameworkEvent
+ * @since 0.5.0 Nitrogen
+ */
+public interface ReconciliationFrameworkRegistration extends AutoCloseable {
+}
<reference id="configurationServiceFactory"
interface="org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationServiceFactory"/>
- <reference id="mastershipChangeServiceManagerFactory"
- interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManagerFactory"/>
+ <reference id="mastershipChangeServiceManager"
+ interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager"/>
<odl:clustered-app-config id="openflowProviderConfig"
binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig"/>
update-method="update"/>
</bean>
- <bean id="mastershipChangeServiceManager"
- factory-ref="mastershipChangeServiceManagerFactory"
- factory-method="newInstance"
- destroy-method="close"
- />
-
- <service ref="mastershipChangeServiceManager" interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager"/>
-
<service ref="configurationService" interface="org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationService"/>
<bean id="openflowPluginProvider"
+++ /dev/null
-/*
- * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * 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.mastership;
-
-import com.google.common.util.concurrent.FutureCallback;
-import java.util.LinkedList;
-import java.util.List;
-import javax.annotation.Nonnull;
-import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
-import org.opendaylight.openflowplugin.api.openflow.lifecycle.MasterChecker;
-import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeRegistration;
-import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeService;
-import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager;
-import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManagerFactory;
-import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MastershipChangeServiceManagerFactoryImpl implements MastershipChangeServiceManagerFactory {
-
- @Override
- public MastershipChangeServiceManager newInstance() {
- return new MastershipChangeServiceManagerImpl();
- }
-
- private static final class MastershipChangeServiceManagerImpl implements
- MastershipChangeServiceManager,
- ReconciliationFrameworkEvent {
-
- private static final Logger LOG = LoggerFactory.getLogger(MastershipChangeServiceManagerImpl.class);
-
- private final List<MastershipChangeService> serviceGroup = new LinkedList<>();
- private ReconciliationFrameworkEvent rfRegistration = null;
- private MasterChecker masterChecker;
-
- @Nonnull
- @Override
- public MastershipChangeRegistration register(@Nonnull MastershipChangeService service) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Mastership change service registered: {}", service);
- }
- MastershipServiceDelegate registration = new MastershipServiceDelegate(service, this);
- serviceGroup.add(registration);
- if (masterChecker.isAnyDeviceMastered()) {
- fireBecomeOwnerAfterRegistration(registration);
- }
- return registration;
-
- }
-
- @Override
- public void reconciliationFrameworkRegistration(@Nonnull ReconciliationFrameworkEvent reconciliationFrameworkEvent) {
- if (rfRegistration != null) {
- LOG.warn("Reconciliation framework listener already registered.");
- } else {
- rfRegistration = reconciliationFrameworkEvent;
- }
- }
-
- @Override
- public void unregister(@Nonnull MastershipChangeService service) {
- serviceGroup.remove(service);
- }
-
- @Override
- public void close() {
- serviceGroup.clear();
- }
-
- @Override
- public void becomeMaster(@Nonnull final DeviceInfo deviceInfo) {
- serviceGroup.forEach(mastershipChangeService -> mastershipChangeService.onBecomeOwner(deviceInfo));
- }
-
- @Override
- public void becomeSlaveOrDisconnect(@Nonnull final DeviceInfo deviceInfo) {
- serviceGroup.forEach(mastershipChangeService -> mastershipChangeService.onLoseOwnership(deviceInfo));
- }
-
- @Override
- public void becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo,
- @Nonnull FutureCallback<ResultState> callback) {
- rfRegistration.onDevicePrepared(deviceInfo, callback);
- }
-
- @Override
- public void setMasterChecker(@Nonnull final MasterChecker masterChecker) {
- this.masterChecker = masterChecker;
- }
-
- @Override
- public boolean isReconciliationFrameworkRegistered() {
- return (rfRegistration != null);
- }
-
- private void fireBecomeOwnerAfterRegistration(@Nonnull final MastershipChangeService service) {
- masterChecker.listOfMasteredDevices().forEach(service::onBecomeOwner);
- }
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.mastership;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.FutureCallback;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.lifecycle.MasterChecker;
+import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeException;
+import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeRegistration;
+import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeService;
+import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager;
+import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent;
+import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class MastershipChangeServiceManagerImpl implements MastershipChangeServiceManager {
+
+ private final List<MastershipChangeService> serviceGroup = new ArrayList<>();
+ private ReconciliationFrameworkEvent rfService = null;
+ private MasterChecker masterChecker;
+
+ @Nonnull
+ @Override
+ public MastershipChangeRegistration register(@Nonnull MastershipChangeService service) {
+ final MastershipServiceDelegate registration =
+ new MastershipServiceDelegate(service, () -> serviceGroup.remove(service));
+ serviceGroup.add(service);
+ if (masterChecker!= null && masterChecker.isAnyDeviceMastered()) {
+ fireBecomeOwnerAfterRegistration(service);
+ }
+ return registration;
+ }
+
+ @Override
+ public ReconciliationFrameworkRegistration reconciliationFrameworkRegistration(
+ @Nonnull ReconciliationFrameworkEvent reconciliationFrameworkEvent) throws MastershipChangeException {
+ if (rfService != null) {
+ throw new MastershipChangeException("Reconciliation framework already registered.");
+ } else {
+ rfService = reconciliationFrameworkEvent;
+ return new ReconciliationFrameworkServiceDelegate(reconciliationFrameworkEvent, () -> rfService = null);
+ }
+ }
+
+ @Override
+ public void close() {
+ serviceGroup.clear();
+ }
+
+ @Override
+ public void becomeMaster(@Nonnull final DeviceInfo deviceInfo) {
+ serviceGroup.forEach(mastershipChangeService -> mastershipChangeService.onBecomeOwner(deviceInfo));
+ }
+
+ @Override
+ public void becomeSlaveOrDisconnect(@Nonnull final DeviceInfo deviceInfo) {
+ if (rfService != null) {
+ rfService.onDeviceDisconnected(deviceInfo);
+ }
+ serviceGroup.forEach(mastershipChangeService -> mastershipChangeService.onLoseOwnership(deviceInfo));
+ }
+
+ @Override
+ public void becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo,
+ @Nonnull FutureCallback<ResultState> callback) {
+ if (rfService != null) {
+ rfService.onDevicePrepared(deviceInfo, callback);
+ }
+ }
+
+ @Override
+ public void setMasterChecker(@Nonnull final MasterChecker masterChecker) {
+ this.masterChecker = masterChecker;
+ }
+
+ @Override
+ public boolean isReconciliationFrameworkRegistered() {
+ return (rfService != null);
+ }
+
+ @VisibleForTesting
+ int serviceGroupListSize() {
+ return serviceGroup.size();
+ }
+
+ private void fireBecomeOwnerAfterRegistration(@Nonnull final MastershipChangeService service) {
+ masterChecker.listOfMasteredDevices().forEach(service::onBecomeOwner);
+ }
+}
import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeRegistration;
import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeService;
import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager;
+import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class MastershipServiceDelegate implements MastershipChangeService, MastershipChangeRegistration {
+ private static final Logger LOG = LoggerFactory.getLogger(MastershipServiceDelegate.class);
+
private final MastershipChangeService service;
- private final MastershipChangeServiceManager manager;
+ private final AutoCloseable unregisterService;
MastershipServiceDelegate(final MastershipChangeService service,
- final MastershipChangeServiceManager manager) {
+ final AutoCloseable unregisterService) {
+ LOG.debug("Mastership change service registered: {}", service);
this.service = service;
- this.manager = manager;
+ this.unregisterService = unregisterService;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("Mastership change service un-registered: {}", service);
+ this.unregisterService.close();
+ this.service.close();
}
@Override
}
@Override
- public void close() throws Exception {
- this.manager.unregister(this.service);
- this.service.close();
+ public String toString() {
+ return service.toString();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.mastership;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.mastership.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
+
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReconciliationFrameworkServiceDelegate implements ReconciliationFrameworkEvent, ReconciliationFrameworkRegistration {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ReconciliationFrameworkServiceDelegate.class);
+
+ private final ReconciliationFrameworkEvent service;
+ private final AutoCloseable unregister;
+
+ ReconciliationFrameworkServiceDelegate(final ReconciliationFrameworkEvent service,
+ final AutoCloseable unregisterService) {
+ LOG.debug("Reconciliation framework service registered: {}", service);
+ this.service = service;
+ this.unregister = unregisterService;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("Reconciliation framework service un-registered: {}", service);
+ this.unregister.close();
+ this.service.close();
+ }
+
+ @Override
+ public void onDevicePrepared(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback<ResultState> callback) {
+ this.service.onDevicePrepared(deviceInfo, callback);
+ }
+
+ @Override
+ public void onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo) {
+ this.service.onDeviceDisconnected(deviceInfo);
+ }
+
+ @Override
+ public String toString() {
+ return service.toString();
+ }
+}
<bean id="configurationServiceFactory" class="org.opendaylight.openflowplugin.impl.configuration.ConfigurationServiceFactoryImpl"/>
<service ref="configurationServiceFactory" interface="org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationServiceFactory"/>
- <bean id="mastershipChangeServiceManagerFactory" class="org.opendaylight.openflowplugin.impl.mastership.MastershipChangeServiceManagerFactoryImpl"/>
- <service ref="mastershipChangeServiceManagerFactory" interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManagerFactory"/>
+ <bean id="mastershipChangeServiceManager" class="org.opendaylight.openflowplugin.impl.mastership.MastershipChangeServiceManagerImpl"/>
+ <service ref="mastershipChangeServiceManager" interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager"/>
</blueprint>
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.mastership;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.lifecycle.MasterChecker;
+import org.opendaylight.openflowplugin.api.openflow.mastership.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MastershipChangeServiceManagerImplTest {
+
+ @Mock
+ private MastershipChangeService service;
+ @Mock
+ private MastershipChangeService secondService;
+ @Mock
+ private DeviceInfo deviceInfo;
+ @Mock
+ private FutureCallback<ResultState> resultStateFutureCallback;
+ @Mock
+ private MasterChecker masterChecker;
+ @Mock
+ private ReconciliationFrameworkEvent event;
+ @Mock
+ private ReconciliationFrameworkEvent secondEvent;
+
+ final private MastershipChangeServiceManager manager = new MastershipChangeServiceManagerImpl();
+ private MastershipChangeRegistration registration;
+ private ReconciliationFrameworkRegistration registrationRF;
+
+ @Before
+ public void setUp() throws Exception {
+ registration = manager.register(service);
+ registrationRF = manager.reconciliationFrameworkRegistration(event);
+ }
+
+ @Test
+ public void register() throws Exception {
+ Assert.assertNotNull(registration);
+ }
+
+ @Test
+ public void registerTwice() throws Exception {
+ MastershipChangeRegistration registration2;
+ registration2 = manager.register(secondService);
+ Assert.assertNotNull(registration);
+ Assert.assertNotNull(registration2);
+ }
+
+ @Test
+ public void uregisterTwice() throws Exception {
+ MastershipChangeRegistration registration2;
+ registration2 = manager.register(secondService);
+ Assert.assertTrue(((MastershipChangeServiceManagerImpl)manager).serviceGroupListSize() == 2);
+ registration.close();
+ Assert.assertTrue(((MastershipChangeServiceManagerImpl)manager).serviceGroupListSize() == 1);
+ registration2.close();
+ Assert.assertTrue(((MastershipChangeServiceManagerImpl)manager).serviceGroupListSize() == 0);
+ }
+
+ @Test
+ public void reconciliationFrameworkRegistration() throws Exception {
+ Assert.assertNotNull(registrationRF);
+ }
+
+ @Test(expected = MastershipChangeException.class)
+ public void reconciliationFrameworkRegistrationTwice() throws Exception {
+ manager.reconciliationFrameworkRegistration(secondEvent);
+ }
+
+ @Test
+ public void unregosteringRF() throws Exception {
+ registrationRF.close();
+ ReconciliationFrameworkRegistration registration1;
+ registration1 = manager.reconciliationFrameworkRegistration(secondEvent);
+ Assert.assertNotNull(registration1);
+ }
+
+ @Test
+ public void becomeMaster() throws Exception {
+ manager.becomeMaster(deviceInfo);
+ Mockito.verify(service).onBecomeOwner(deviceInfo);
+ manager.becomeSlaveOrDisconnect(deviceInfo);
+ Mockito.verify(service).onLoseOwnership(deviceInfo);
+ }
+
+ @Test
+ public void becomeMasterBeforeDS() throws Exception {
+ manager.becomeMasterBeforeSubmittedDS(deviceInfo, resultStateFutureCallback);
+ Mockito.verify(event).onDevicePrepared(deviceInfo, resultStateFutureCallback);
+ }
+
+ @Test
+ public void isReconciliationFrameworkRegistered() throws Exception {
+ Assert.assertTrue(manager.isReconciliationFrameworkRegistered());
+ registrationRF.close();
+ Assert.assertFalse(manager.isReconciliationFrameworkRegistered());
+ }
+
+ @Test
+ public void evokeEventAfterRegistration() throws Exception {
+ List<DeviceInfo> deviceInfos = new ArrayList<>();
+ deviceInfos.add(deviceInfo);
+ manager.setMasterChecker(masterChecker);
+ Mockito.when(masterChecker.isAnyDeviceMastered()).thenReturn(true);
+ Mockito.when(masterChecker.listOfMasteredDevices()).thenReturn(deviceInfos);
+ manager.register(secondService);
+ Mockito.verify(secondService).onBecomeOwner(deviceInfo);
+ }
+
+}