<artifactId>commons-lang3</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<artifactId>mdsal-singleton-dom-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-dom-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-singleton-binding-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-binding-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
<groupId>${project.groupId}</groupId>
<artifactId>mdsal-eos-binding-adapter</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-common-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-common-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-dom-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-dom-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-singleton-binding-impl</artifactId>
+ </dependency>
<!-- Binding MD-SAL & Java Binding -->
<dependency>
<bundle>mvn:org.opendaylight.mdsal/mdsal-eos-common-spi/{{VERSION}}</bundle>
</feature>
- <feature name='odl-mdsal-eos-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Common'>
+ <feature name='odl-mdsal-eos-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: DOM'>
<feature version='${project.version}'>odl-mdsal-eos-common</feature>
<bundle>mvn:org.opendaylight.mdsal/mdsal-eos-dom-api/{{VERSION}}</bundle>
</feature>
- <feature name='odl-mdsal-eos-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Common'>
+ <feature name='odl-mdsal-eos-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Binding'>
<feature version='${project.version}'>odl-mdsal-eos-dom</feature>
<feature version='${project.version}'>odl-mdsal-binding-dom-adapter</feature>
<bundle>mvn:org.opendaylight.mdsal/mdsal-eos-binding-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.mdsal/mdsal-eos-binding-adapter/{{VERSION}}</bundle>
</feature>
+ <feature name='odl-mdsal-singleton-common' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: Common'>
+ <feature version='${project.version}'>odl-mdsal-eos-common</feature>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-common-api/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-common-spi/{{VERSION}}</bundle>
+ </feature>
+
+ <feature name='odl-mdsal-singleton-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: DOM'>
+ <feature version='${project.version}'>odl-mdsal-singleton-common</feature>
+ <feature version='${project.version}'>odl-mdsal-eos-dom</feature>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-dom-api/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-dom-impl/{{VERSION}}</bundle>
+ </feature>
+
+ <feature name='odl-mdsal-singleton-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: Binding'>
+ <feature version='${project.version}'>odl-mdsal-singleton-common</feature>
+ <feature version='${project.version}'>odl-mdsal-eos-binding</feature>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-binding-api/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-binding-impl/{{VERSION}}</bundle>
+ </feature>
+
</features>
<artifactId>yang-data-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>singleton-service</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>mdsal-singleton-binding-impl</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-eos-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-common-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-common-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.singleton.binding.impl;
+
+import org.opendaylight.mdsal.eos.binding.api.Entity;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListener;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.binding.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.spi.AbstractClusterSingletonServiceProviderImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.core.general.entity.rev150930.EntityKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Binding version of {@link AbstractClusterSingletonServiceProviderImpl}
+ */
+public final class ClusterSingletonServiceProviderImpl extends
+ AbstractClusterSingletonServiceProviderImpl<InstanceIdentifier<?>, Entity,
+ EntityOwnershipChange,
+ EntityOwnershipListener,
+ EntityOwnershipService,
+ EntityOwnershipListenerRegistration>
+ implements ClusterSingletonServiceProvider {
+
+ /**
+ * Initialization all needed class internal property for {@link ClusterSingletonServiceProviderImpl}
+ *
+ * @param entityOwnershipService - we need only {@link GenericEntityOwnershipService}
+ */
+ public ClusterSingletonServiceProviderImpl(final EntityOwnershipService entityOwnershipService) {
+ super(entityOwnershipService);
+ }
+
+ @Override
+ protected final Entity createEntity(final String type, final String ident) {
+ return new Entity(type, ident);
+ }
+
+ @Override
+ protected final EntityOwnershipListenerRegistration registerListener(final String type,
+ final EntityOwnershipService eos) {
+ return eos.registerListener(type, this);
+ }
+
+ @Override
+ protected final String getServiceIdentifierFromEntity(final Entity entity) {
+ final InstanceIdentifier<?> ii = entity.getIdentifier();
+ final EntityKey entityKey = ii.firstKeyOf(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.core.general.entity.rev150930.Entity.class);
+ return entityKey.getName();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.singleton.binding.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.eos.binding.api.Entity;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+
+/**
+ * Testing {@link ClusterSingletonServiceProviderImpl}
+ */
+public class ClusterSingletonServiceProviderImplTest {
+
+ private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+ private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
+ private static final String SERVICE_NAME = "testServiceName";
+
+ @Mock
+ private EntityOwnershipService mockEos;
+ @Mock
+ private EntityOwnershipCandidateRegistration mockEntityCandReg;
+ @Mock
+ private EntityOwnershipCandidateRegistration mockDoubleEntityCandReg;
+ @Mock
+ private EntityOwnershipListenerRegistration mockEosEntityListReg;
+ @Mock
+ private EntityOwnershipListenerRegistration mockEosDoubleEntityListReg;
+
+ private ClusterSingletonServiceProviderImpl clusterSingletonServiceProvider;
+ private TestClusterSingletonServiceInstance clusterSingletonService;
+ private TestClusterSingletonServiceInstance clusterSingletonService2;
+
+ private final Entity entity = new Entity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+ private final Entity doubleEntity = new Entity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+
+ /**
+ * Initialization functionality for every Tests in this suite
+ *
+ * @throws Exception
+ */
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ doNothing().when(mockEosEntityListReg).close();
+ doNothing().when(mockEosDoubleEntityListReg).close();
+ doNothing().when(mockEntityCandReg).close();
+ doNothing().when(mockDoubleEntityCandReg).close();
+ doReturn(mockEosEntityListReg).when(mockEos).registerListener(eq(SERVICE_ENTITY_TYPE),
+ any(ClusterSingletonServiceProviderImpl.class));
+ doReturn(mockEosDoubleEntityListReg).when(mockEos).registerListener(eq(CLOSE_SERVICE_ENTITY_TYPE),
+ any(ClusterSingletonServiceProviderImpl.class));
+ doReturn(mockEntityCandReg).when(mockEos).registerCandidate(entity);
+ doReturn(mockDoubleEntityCandReg).when(mockEos).registerCandidate(doubleEntity);
+
+ clusterSingletonServiceProvider = new ClusterSingletonServiceProviderImpl(mockEos);
+ clusterSingletonServiceProvider.initializeProvider();
+ verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+
+ clusterSingletonService = new TestClusterSingletonServiceInstance();
+ clusterSingletonService2 = new TestClusterSingletonServiceInstance();
+
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks NullPointer for null {@link EntityOwnershipService} input value
+ *
+ * @throws Exception
+ */
+ @Test(expected = NullPointerException.class)
+ public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
+ clusterSingletonServiceProvider = new ClusterSingletonServiceProviderImpl(null);
+ }
+
+ /**
+ * Test GoldPath for close {@link ClusterSingletonServiceProviderImpl}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceProviderTest() throws Exception {
+ verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ clusterSingletonServiceProvider.close();
+ verify(mockEosEntityListReg).close();
+ verify(mockEosDoubleEntityListReg).close();
+ }
+
+ /**
+ * Test parser ServiceIdentifier from Entity
+ *
+ * @throws Exception
+ */
+ @Test
+ public void makeEntityClusterSingletonServiceProviderTest() throws Exception {
+ final Entity testEntity = clusterSingletonServiceProvider.createEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+ Assert.assertEquals(entity, testEntity);
+ final Entity testDbEn = clusterSingletonServiceProvider.createEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+ Assert.assertEquals(doubleEntity, testDbEn);
+ }
+
+ /**
+ * Test parser ServiceIdentifier from Entity
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getIdentifierClusterSingletonServiceProviderTest() throws Exception {
+ final String entityIdentifier = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(entity);
+ Assert.assertEquals(SERVICE_NAME, entityIdentifier);
+ final String doubleEntityId = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(doubleEntity);
+ Assert.assertEquals(SERVICE_NAME, doubleEntityId);
+ }
+
+ /**
+ * Test GoldPath for initialization {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void initializationClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result SLAVE {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void slaveInitClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result SLAVE, but NO-MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void slaveInitNoMasterClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlaveNoMaster());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitSlaveDoubleCandidateClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitClusterSingletonServiceTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTwoAddDuringWaitPhaseServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTowServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks CandidateAlreadyRegisteredException processing in initialization phase
+ *
+ * @throws Exception
+ */
+ @Test
+ public void initializationClusterSingletonServiceCandidateAlreadyRegistredTest() throws Exception {
+ doThrow(CandidateAlreadyRegisteredException.class).when(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNull(reg);
+ }
+
+ /**
+ * Test GoldPath for lostLeadership during tryToTakeLeadership with ownership result MASTER
+ * {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void lostLeadershipDuringTryToTakeLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for lostLeadership with ownership result MASTER-TO-SLAVE {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void lostLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks umexpected change for MASTER-TO-SLAVE double Candidate role change
+ *
+ * @throws Exception
+ */
+ @Test
+ public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg).close();
+ }
+
+ /**
+ * Test checks inJeopardy Cluster Node state for Master Instance
+ *
+ * @throws Exception
+ */
+ @Test
+ public void inJeopardyMasterTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg).close();
+ }
+
+ /**
+ * Test checks inJeopardy Cluster Node state for Slave Instance
+ *
+ * @throws Exception
+ */
+ @Test
+ public void inJeopardySlaveTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationNoRoleTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationNoRoleTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationSlaveTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationSlaveTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change
+ *
+ * @throws Exception
+ */
+ @Test
+ public void tryToTakeLeaderForClosedServiceRegistrationTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ reg.close();
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ private EntityOwnershipChange getEntityToMaster() {
+ return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, true, true));
+ }
+
+ private EntityOwnershipChange getEntityToSlave() {
+ return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(true, false, true));
+ }
+
+ private EntityOwnershipChange getInitEntityToSlave() {
+ return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, true));
+ }
+
+ private EntityOwnershipChange getInitEntityToSlaveNoMaster() {
+ return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false));
+ }
+
+ private EntityOwnershipChange getDoubleEntityToMaster() {
+ return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, true, true));
+ }
+
+ private EntityOwnershipChange getInitDoubleEntityToSlave() {
+ return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, false, true));
+ }
+
+ private EntityOwnershipChange getDoubleEntityToSlave() {
+ return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(true, false, true));
+ }
+
+ private EntityOwnershipChange getEntityToJeopardy() {
+ return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false), true);
+ }
+
+ /**
+ * Base states for AbstractClusterProjectProvider
+ */
+ static enum TestClusterSingletonServiceState {
+ /**
+ * State represents a correct Instantiated process
+ */
+ STARTED,
+ /**
+ * State represents a correct call abstract method instantiatingProject
+ */
+ INITIALIZED,
+ /**
+ * State represents a correct call abstract method destryingProject
+ */
+ DESTROYED;
+ }
+
+ /**
+ * Test implementation of {@link ClusterSingletonService}
+ */
+ class TestClusterSingletonServiceInstance implements ClusterSingletonService {
+
+ private final ServiceGroupIdentifier SERVICE_IDENT = ServiceGroupIdentifier.create(SERVICE_NAME);
+ private TestClusterSingletonServiceState serviceState;
+
+ public TestClusterSingletonServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
+ }
+
+ @Override
+ public void instantiateServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.STARTED;
+ }
+
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.DESTROYED;
+ return Futures.immediateFuture(null);
+ }
+
+ public TestClusterSingletonServiceState getServiceState() {
+ return serviceState;
+ }
+
+ @Override
+ public ServiceGroupIdentifier getIdentifier() {
+ return SERVICE_IDENT;
+ }
+ }
+
+}
package org.opendaylight.mdsal.singleton.common.spi;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.eos.common.api.GenericEntity;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.CommonClusterSingletonServiceProvider;
+import org.opendaylight.yangtools.concepts.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Abstract class {@link AbstractClusterSingletonServiceProviderImpl} represents implementations of
- * {@link org.opendaylight.mdsal.singleton.common.api.CommonClusterSingletonServiceProvider}.
+ * {@link CommonClusterSingletonServiceProvider} and it implements {@link GenericEntityOwnershipListener}
+ * for providing OwnershipChange for all registered {@link ClusterSingletonServiceGroup} entity
+ * candidate.
+ *
+ * @param <P> the instance identifier path type
+ * @param <E> the GenericEntity type
+ * @param <C> the GenericEntityOwnershipChange type
+ * @param <G> the GenericEntityOwnershipListener type
+ * @param <S> the GenericEntityOwnershipService type
+ * @param <R> the GenericEntityOwnershipListenerRegistration type
*/
-public abstract class AbstractClusterSingletonServiceProviderImpl {
+public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path<P>, E extends GenericEntity<P>,
+ C extends GenericEntityOwnershipChange<P, E>,
+ G extends GenericEntityOwnershipListener<P, C>,
+ S extends GenericEntityOwnershipService<P, E, G>,
+ R extends GenericEntityOwnershipListenerRegistration<P, G>>
+ implements CommonClusterSingletonServiceProvider, GenericEntityOwnershipListener<P, C> {
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName());
+
+ private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+ private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
+
+ private final S entityOwnershipService;
+ private final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> serviceGroupMap = new ConcurrentHashMap<>();
+
+ /* EOS Entity Listeners Registration */
+ private R serviceEntityListenerReg;
+ private R asyncCloseEntityListenerReg;
+
+ /**
+ * Class constructor
+ *
+ * @param entityOwnershipService relevant EOS
+ */
+ protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) {
+ this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
+ }
+
+ /**
+ * This method must be called once on startup to initialize this provider.
+ */
+ public final void initializeProvider() {
+ LOG.debug("Initialization method for ClusterSingletonService Provider {}", this.getClass().getName());
+ this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService);
+ this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService);
+ }
+
+ @Override
+ public final ClusterSingletonServiceRegistration registerClusterSingletonService(
+ @CheckForNull final ClusterSingletonService service) {
+ LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service,
+ this.getClass().getName());
+
+ Preconditions.checkArgument(service != null);
+ Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()),
+ "ClusterSingletonService idetnifier can not be null. {}", service);
+
+ final String serviceIdentifier = service.getIdentifier().getValue();
+ ClusterSingletonServiceGroup<P, E, C> serviceGroup = serviceGroupMap.get(serviceIdentifier);
+ if (serviceGroup == null) {
+ final E mainEntity = createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier);
+ final E closeEntity = createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier);
+ serviceGroup = new ClusterSingletonServiceGroupImpl<>(serviceIdentifier,
+ mainEntity, closeEntity, entityOwnershipService, serviceGroupMap);
+ serviceGroupMap.put(service.getIdentifier().getValue(), serviceGroup);
+ serviceGroup.initializationClusterSingletonGroup();
+ }
+ return serviceGroup.registerService(service);
+ }
+
+ @Override
+ public final void close() {
+ LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
+
+ if (serviceEntityListenerReg != null) {
+ serviceEntityListenerReg.close();
+ serviceEntityListenerReg = null;
+ }
+
+ final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
+
+ for (final ClusterSingletonServiceGroup<P, E, C> serviceGroup : serviceGroupMap.values()) {
+ listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup());
+ }
+
+ final ListenableFuture<List<List<Void>>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
+ Futures.addCallback(finalCloseFuture, new FutureCallback<List<List<Void>>>() {
+
+ @Override
+ public void onSuccess(final List<List<Void>> result) {
+ cleaningProvider(null);
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ cleaningProvider(t);
+ }
+ });
+ }
+
+ @Override
+ public final void ownershipChanged(final C ownershipChange) {
+ LOG.debug("Ownership change for ClusterSingletonService Provider {}", ownershipChange);
+ final String serviceIdentifier = getServiceIdentifierFromEntity(ownershipChange.getEntity());
+ final ClusterSingletonServiceGroup<P, E, C> serviceHolder = serviceGroupMap.get(serviceIdentifier);
+ if (serviceHolder != null) {
+ serviceHolder.ownershipChanged(ownershipChange);
+ } else {
+ LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier);
+ }
+ }
+
+ /**
+ * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type
+ * EntityOwnershipListenerRegistration.
+ *
+ * @param entityType the type of the entity
+ * @param entityOwnershipServiceInst - EOS type
+ * @return instance of EntityOwnershipListenerRegistration
+ */
+ protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst);
+
+ /**
+ * Creates an extended {@link GenericEntity} instance.
+ *
+ * @param entityType the type of the entity
+ * @param entityIdentifier the identifier of the entity
+ * @return instance of Entity extended GenericEntity type
+ */
+ protected abstract E createEntity(final String entityType, final String entityIdentifier);
+
+ /**
+ * Method is responsible for parsing ServiceGroupIdentifier from E entity.
+ *
+ * @param entity
+ * @return ServiceGroupIdentifier parsed from entity key value.
+ */
+ protected abstract String getServiceIdentifierFromEntity(final E entity);
- // TODO: add implementation
+ /**
+ * Method is called async. from close method in end of Provider lifecycle.
+ *
+ * @param t Throwable (needs for log)
+ */
+ protected final void cleaningProvider(@Nullable final Throwable t) {
+ LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName());
+ if (t != null) {
+ LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}", this.getClass().getName(), t);
+ }
+ if (asyncCloseEntityListenerReg != null) {
+ asyncCloseEntityListenerReg.close();
+ asyncCloseEntityListenerReg = null;
+ }
+ serviceGroupMap.clear();
+ }
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>singleton-service</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>mdsal-singleton-dom-impl</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-common-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-common-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-common-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-singleton-dom-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.singleton.dom.impl;
+
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.common.spi.AbstractClusterSingletonServiceProviderImpl;
+import org.opendaylight.mdsal.singleton.dom.api.DOMClusterSingletonServiceProvider;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+
+/**
+ * Binding version of {@link AbstractClusterSingletonServiceProviderImpl}
+ */
+public final class DOMClusterSingletonServiceProviderImpl extends
+ AbstractClusterSingletonServiceProviderImpl<YangInstanceIdentifier, DOMEntity,
+ DOMEntityOwnershipChange,
+ DOMEntityOwnershipListener,
+ DOMEntityOwnershipService,
+ DOMEntityOwnershipListenerRegistration>
+ implements DOMClusterSingletonServiceProvider {
+
+ /**
+ * Initialization all needed class internal property for {@link DOMClusterSingletonServiceProviderImpl}
+ *
+ * @param entityOwnershipService - we need only {@link GenericEntityOwnershipService}
+ */
+ public DOMClusterSingletonServiceProviderImpl(final DOMEntityOwnershipService entityOwnershipService) {
+ super(entityOwnershipService);
+ }
+
+ @Override
+ protected final DOMEntity createEntity(final String type, final String ident) {
+ return new DOMEntity(type, ident);
+ }
+
+ @Override
+ protected final DOMEntityOwnershipListenerRegistration registerListener(final String type,
+ final DOMEntityOwnershipService eos) {
+ return eos.registerListener(type, this);
+ }
+
+ @Override
+ protected String getServiceIdentifierFromEntity(final DOMEntity entity) {
+ final YangInstanceIdentifier yii = entity.getIdentifier();
+ final NodeIdentifierWithPredicates niiwp = (NodeIdentifierWithPredicates) yii.getLastPathArgument();
+ return niiwp.getKeyValues().values().iterator().next().toString();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.singleton.dom.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+
+/**
+ * Testing {@link DOMClusterSingletonServiceProviderImpl} implementation
+ */
+public class DOMClusterSingletonServiceProviderImplTest {
+
+ private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+ private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
+ private static final String SERVICE_NAME = "testServiceName";
+
+ @Mock
+ private DOMEntityOwnershipService mockEos;
+ @Mock
+ private DOMEntityOwnershipCandidateRegistration mockEntityCandReg;
+ @Mock
+ private DOMEntityOwnershipCandidateRegistration mockDoubleEntityCandReg;
+ @Mock
+ private DOMEntityOwnershipListenerRegistration mockEosEntityListReg;
+ @Mock
+ private DOMEntityOwnershipListenerRegistration mockEosDoubleEntityListReg;
+
+ private DOMClusterSingletonServiceProviderImpl clusterSingletonServiceProvider;
+ private TestClusterSingletonServiceInstance clusterSingletonService;
+ private TestClusterSingletonServiceInstance clusterSingletonService2;
+
+ private final DOMEntity entity = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+ private final DOMEntity doubleEntity = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+
+ /**
+ * Initialization functionality for every Tests in this suite
+ *
+ * @throws Exception
+ */
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ doNothing().when(mockEosEntityListReg).close();
+ doNothing().when(mockEosDoubleEntityListReg).close();
+ doNothing().when(mockEntityCandReg).close();
+ doNothing().when(mockDoubleEntityCandReg).close();
+ doReturn(mockEosEntityListReg).when(mockEos).registerListener(eq(SERVICE_ENTITY_TYPE),
+ any(DOMClusterSingletonServiceProviderImpl.class));
+ doReturn(mockEosDoubleEntityListReg).when(mockEos).registerListener(eq(CLOSE_SERVICE_ENTITY_TYPE),
+ any(DOMClusterSingletonServiceProviderImpl.class));
+ doReturn(mockEntityCandReg).when(mockEos).registerCandidate(entity);
+ doReturn(mockDoubleEntityCandReg).when(mockEos).registerCandidate(doubleEntity);
+
+ clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(mockEos);
+ clusterSingletonServiceProvider.initializeProvider();
+ verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+
+ clusterSingletonService = new TestClusterSingletonServiceInstance();
+ clusterSingletonService2 = new TestClusterSingletonServiceInstance();
+
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks NullPointer for null {@link DOMEntityOwnershipService} input value
+ *
+ * @throws Exception
+ */
+ @Test(expected = NullPointerException.class)
+ public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
+ clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(null);
+ }
+
+ /**
+ * Test GoldPath for close {@link DOMClusterSingletonServiceProviderImpl}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceProviderTest() throws Exception {
+ verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+ clusterSingletonServiceProvider.close();
+ verify(mockEosEntityListReg).close();
+ verify(mockEosDoubleEntityListReg).close();
+ }
+
+ /**
+ * Test parser ServiceIdentifier from Entity
+ *
+ * @throws Exception
+ */
+ @Test
+ public void makeEntityClusterSingletonServiceProviderTest() throws Exception {
+ final DOMEntity testEntity = clusterSingletonServiceProvider.createEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+ Assert.assertEquals(entity, testEntity);
+ final DOMEntity testDbEn = clusterSingletonServiceProvider.createEntity(CLOSE_SERVICE_ENTITY_TYPE,
+ SERVICE_NAME);
+ Assert.assertEquals(doubleEntity, testDbEn);
+ }
+
+ /**
+ * Test parser ServiceIdentifier from Entity
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getIdentifierClusterSingletonServiceProviderTest() throws Exception {
+ final String entityIdentifier = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(entity);
+ Assert.assertEquals(SERVICE_NAME, entityIdentifier);
+ final String doubleEntityId = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(doubleEntity);
+ Assert.assertEquals(SERVICE_NAME, doubleEntityId);
+ }
+
+ /**
+ * Test GoldPath for initialization {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void initializationClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result SLAVE {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void slaveInitClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result SLAVE, but NO-MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void slaveInitNoMasterClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlaveNoMaster());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitSlaveDoubleCandidateClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void masterInitClusterSingletonServiceTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTwoAddDuringWaitPhaseServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void takeLeadershipClusterSingletonServiceTowServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks CandidateAlreadyRegisteredException processing in initialization phase
+ *
+ * @throws Exception
+ */
+ @Test
+ public void initializationClusterSingletonServiceCandidateAlreadyRegistredTest() throws Exception {
+ doThrow(CandidateAlreadyRegisteredException.class).when(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNull(reg);
+ }
+
+ /**
+ * Test GoldPath for lostLeadership during tryToTakeLeadership with ownership result MASTER
+ * {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void lostLeadershipDuringTryToTakeLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test GoldPath for lostLeadership with ownership result MASTER-TO-SLAVE {@link ClusterSingletonService}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void lostLeadershipClusterSingletonServiceTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks umexpected change for MASTER-TO-SLAVE double Candidate role change
+ *
+ * @throws Exception
+ */
+ @Test
+ public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg).close();
+ }
+
+ /**
+ * Test checks inJeopardy Cluster Node state for Master Instance
+ *
+ * @throws Exception
+ */
+ @Test
+ public void inJeopardyMasterTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg).close();
+ }
+
+ /**
+ * Test checks inJeopardy Cluster Node state for Slave Instance
+ *
+ * @throws Exception
+ */
+ @Test
+ public void inJeopardySlaveTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ verify(mockEos, never()).registerCandidate(doubleEntity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationNoRoleTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationNoRoleTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationSlaveTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationSlaveTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ verify(mockEos).registerCandidate(entity);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg).close();
+ verify(mockDoubleEntityCandReg).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ }
+
+ /**
+ * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+ *
+ * @throws Exception
+ */
+ @Test
+ public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ reg.close();
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ /**
+ * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change
+ *
+ * @throws Exception
+ */
+ @Test
+ public void tryToTakeLeaderForClosedServiceRegistrationTest() throws Exception {
+ final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService);
+ Assert.assertNotNull(reg);
+ final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+ .registerClusterSingletonService(clusterSingletonService2);
+ Assert.assertNotNull(reg2);
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+ verify(mockEos).registerCandidate(entity);
+ reg.close();
+ clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+ verify(mockEos).registerCandidate(doubleEntity);
+ clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ verify(mockEosEntityListReg, never()).close();
+ verify(mockEosDoubleEntityListReg, never()).close();
+ verify(mockEntityCandReg, never()).close();
+ verify(mockDoubleEntityCandReg, never()).close();
+ Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+ Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+ }
+
+ private DOMEntityOwnershipChange getEntityToMaster() {
+ return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, true, true));
+ }
+
+ private DOMEntityOwnershipChange getEntityToSlave() {
+ return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(true, false, true));
+ }
+
+ private DOMEntityOwnershipChange getInitEntityToSlave() {
+ return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, true));
+ }
+
+ private DOMEntityOwnershipChange getInitEntityToSlaveNoMaster() {
+ return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false));
+ }
+
+ private DOMEntityOwnershipChange getDoubleEntityToMaster() {
+ return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, true, true));
+ }
+
+ private DOMEntityOwnershipChange getInitDoubleEntityToSlave() {
+ return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, false, true));
+ }
+
+ private DOMEntityOwnershipChange getDoubleEntityToSlave() {
+ return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(true, false, true));
+ }
+
+ private DOMEntityOwnershipChange getEntityToJeopardy() {
+ return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false), true);
+ }
+
+ /**
+ * Base states for AbstractClusterProjectProvider
+ */
+ static enum TestClusterSingletonServiceState {
+ /**
+ * State represents a correct Instantiated process
+ */
+ STARTED,
+ /**
+ * State represents a correct call abstract method instantiatingProject
+ */
+ INITIALIZED,
+ /**
+ * State represents a correct call abstract method destryingProject
+ */
+ DESTROYED;
+ }
+
+ /**
+ * Test implementation of {@link ClusterSingletonService}
+ */
+ class TestClusterSingletonServiceInstance implements ClusterSingletonService {
+
+ private final ServiceGroupIdentifier SERVICE_IDENT = ServiceGroupIdentifier.create(SERVICE_NAME);
+ private TestClusterSingletonServiceState serviceState;
+
+ public TestClusterSingletonServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
+ }
+
+ @Override
+ public void instantiateServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.STARTED;
+ }
+
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+ this.serviceState = TestClusterSingletonServiceState.DESTROYED;
+ return Futures.immediateFuture(null);
+ }
+
+ public TestClusterSingletonServiceState getServiceState() {
+ return serviceState;
+ }
+
+ @Override
+ public ServiceGroupIdentifier getIdentifier() {
+ return SERVICE_IDENT;
+ }
+ }
+}
<modules>
<module>mdsal-singleton-common-api</module>
+ <module>mdsal-singleton-common-spi</module>
<module>mdsal-singleton-dom-api</module>
+ <module>mdsal-singleton-dom-impl</module>
<module>mdsal-singleton-binding-api</module>
- <module>mdsal-singleton-common-spi</module>
+ <module>mdsal-singleton-binding-impl</module>
</modules>