Common class for clustering operations for each module.
Change-Id: If401eba45155e07846f025340b6499969213e7bb
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
<type>xml</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mappingservice.clustering</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mappingservice.dsbackend</artifactId>
<feature version="${mdsal.version}">odl-mdsal-broker</feature>
<feature version='${project.version}'>odl-lispflowmapping-models</feature>
<feature version="${project.version}">odl-lispflowmapping-inmemorydb</feature>
+ <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.clustering/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.dsbackend/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.mapcache/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.implementation/{{VERSION}}</bundle>
<feature version="${mdsal.version}">odl-mdsal-broker</feature>
<feature version='${project.version}'>odl-lispflowmapping-models</feature>
<feature version="${project.version}">odl-lispflowmapping-inmemorydb</feature>
+ <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.clustering/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.dsbackend/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.mapcache/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.southbound/{{VERSION}}</bundle>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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
+ -->
+
+<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.lispflowmapping</groupId>
+ <artifactId>mappingservice-parent</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>mappingservice.clustering</artifactId>
+ <packaging>bundle</packaging>
+ <name>Mapping Service Clustering (mappingservice.clustering)</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <!-- Enforce odlparent checkstyle -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <includeTestSourceDirectory>true</includeTestSourceDirectory>
+ <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <!--
+ 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.lispflowmapping.clustering;
+
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_NAME;
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_TYPE;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.lispflowmapping.clustering.api.ClusterNodeModuleSwitcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class responsible for turning on|off module in node cluster.
+ */
+public class ClusterNodeModulSwitcherImpl implements EntityOwnershipListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClusterNodeModulSwitcherImpl.class);
+ private final EntityOwnershipService entityOwnershipService;
+ private final Entity entity;
+ private boolean moduleIsRunning = true;
+ private ClusterNodeModuleSwitcher module;
+
+ public ClusterNodeModulSwitcherImpl(final EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ this.entityOwnershipService.registerListener(LISPFLOWMAPPING_ENTITY_NAME, this);
+ entity = new Entity(LISPFLOWMAPPING_ENTITY_NAME, LISPFLOWMAPPING_ENTITY_TYPE);
+ try {
+ this.entityOwnershipService.registerCandidate(entity);
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.debug("Candidate already registered. Trace: {}", e);
+ }
+ }
+
+ @Override
+ public void ownershipChanged(final EntityOwnershipChange entityOwnershipChange) {
+ LOG.debug("Entity ownership change message received.");
+ switchModuleState(entityOwnershipChange.isOwner());
+ }
+
+ public void switchModuleByEntityOwnership() {
+ switchModuleState(isMaster());
+ }
+
+ private void switchModuleState(final boolean isOwner) {
+ if (module != null) {
+ if (!isOwner && moduleIsRunning) {
+ module.stopModule();
+ moduleIsRunning = false;
+ LOG.debug("Module {} was stopped.", module.getClass().getName());
+ } else if (isOwner && !moduleIsRunning) {
+ module.startModule();
+ moduleIsRunning = true;
+ LOG.debug("Module {} was restarted.", module.getClass().getName());
+ }
+ } else {
+ LOG.debug("Module wasn't initialized yet.");
+ }
+ }
+
+ public boolean isMaster() {
+ final Optional<EntityOwnershipState> ownershipState = entityOwnershipService.getOwnershipState(entity);
+ if (ownershipState.isPresent()) {
+ return ownershipState.get().isOwner();
+ } else {
+ LOG.debug("Ownership state information wasn't present in entity ownership service.");
+ }
+ return false;
+ }
+
+ public void setModule(final ClusterNodeModuleSwitcher module) {
+ this.module = module;
+ }
+}
--- /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.lispflowmapping.clustering.api;
+
+/**
+ * Interface specify operations necessary to turn on|off module in node cluster.
+ */
+public interface ClusterNodeModuleSwitcher {
+
+ void startModule();
+
+ void stopModule();
+
+}
--- /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.lispflowmapping.clustering.util;
+
+public final class ClusteringUtil {
+
+ public static final String LISPFLOWMAPPING_ENTITY_NAME = "lispflowmapping";
+ public static final String LISPFLOWMAPPING_ENTITY_TYPE = "application";
+
+ private ClusteringUtil() {
+ throw new UnsupportedOperationException();
+ }
+
+}
--- /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.lispflowmapping.clustering;
+
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_NAME;
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_TYPE;
+
+import com.google.common.base.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.lispflowmapping.clustering.api.ClusterNodeModuleSwitcher;
+
+public class ClusterNodeModulSwitcherImplTest {
+
+ private EntityOwnershipService entityOwnershipServiceMocked;
+ private ClusterNodeModulSwitcherImpl clusterNodeModulSwitcherImpl;
+ private ClusterNodeModuleSwitcher module;
+ private Entity entity = new Entity(LISPFLOWMAPPING_ENTITY_NAME, LISPFLOWMAPPING_ENTITY_TYPE);
+
+ @Before
+ public void init() {
+ entityOwnershipServiceMocked = Mockito.mock(EntityOwnershipService.class);
+ clusterNodeModulSwitcherImpl = new ClusterNodeModulSwitcherImpl(entityOwnershipServiceMocked);
+ module = Mockito.mock(ClusterNodeModuleSwitcher.class);
+ }
+
+ @Test
+ public void constructorCallTest() throws CandidateAlreadyRegisteredException {
+ Mockito.verify(entityOwnershipServiceMocked).registerListener(Matchers.eq(LISPFLOWMAPPING_ENTITY_NAME),
+ Matchers.any(ClusterNodeModulSwitcherImpl.class));
+ Mockito.verify(entityOwnershipServiceMocked).registerCandidate(Matchers.eq(entity));
+ }
+
+ @Test
+ public void ownershipChangedTest() {
+ //is not owner
+ ownershipChanged(false);
+ Mockito.verify(module).stopModule();
+ //is owner
+ ownershipChanged(true);
+ Mockito.verify(module).startModule();
+ }
+
+ @Test
+ public void isMasterTest_OptionalAbsent() {
+ Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+ .absent
+ ());
+ Assert.assertFalse(clusterNodeModulSwitcherImpl.isMaster());
+ }
+
+ @Test
+ public void isMasterTest_True() {
+ Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+ .of(new EntityOwnershipState(true, true)));
+ Assert.assertTrue(clusterNodeModulSwitcherImpl.isMaster());
+ }
+
+ @Test
+ public void isMasterTest_False() {
+ Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+ .of(new EntityOwnershipState(false, true)));
+ Assert.assertFalse(clusterNodeModulSwitcherImpl.isMaster());
+ }
+
+ @Test
+ public void switchModuleByEntityOwnershipTest() {
+ Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+ .of(new EntityOwnershipState(false, true)));
+ clusterNodeModulSwitcherImpl.switchModuleByEntityOwnership();
+ }
+
+ private void ownershipChanged(boolean isOwner) {
+ final EntityOwnershipChange entityOwnershipChangeMock = Mockito.mock(EntityOwnershipChange.class);
+ clusterNodeModulSwitcherImpl.setModule(module);
+ Mockito.when(entityOwnershipChangeMock.isOwner()).thenReturn(isOwner);
+ clusterNodeModulSwitcherImpl.ownershipChanged(entityOwnershipChangeMock);
+ }
+}
*/
package org.opendaylight.lispflowmapping.implementation.mdsal;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
* The superclass for the different MD-SAL data change event listeners.
*
*/
-public abstract class AbstractDataListener<T extends DataObject> implements DataTreeChangeListener<T> {
+public abstract class AbstractDataListener<T extends DataObject> implements ClusteredDataTreeChangeListener<T> {
private DataBroker broker;
private InstanceIdentifier<T> path;
private ListenerRegistration<DataTreeChangeListener<T>> registration;
<modules>
<module>lisp-proto</module>
<module>api</module>
+ <module>clustering</module>
<module>inmemorydb</module>
<module>dsbackend</module>
<module>mapcache</module>
import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
* DataListener for all AuthenticationKey modification events.
*
*/
-public class AuthenticationKeyDataListener implements DataTreeChangeListener<AuthenticationKey> {
+public class AuthenticationKeyDataListener implements ClusteredDataTreeChangeListener<AuthenticationKey> {
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationKeyDataListener.class);
private final SimpleMapCache smc;