From 3253c4174c87236130310a0c901dcad2416619dd Mon Sep 17 00:00:00 2001 From: Moiz Raja Date: Sun, 11 Oct 2015 00:48:34 -0700 Subject: [PATCH] Add a mechanism to read the entity owner selection strategies from a config file Change-Id: Ie951e4f83aaf38f00e959f4243820a88cb988788 Signed-off-by: Moiz Raja Signed-off-by: Tom Pantelis --- .../EntityOwnerSelectionStrategyConfig.java | 4 + ...ityOwnerSelectionStrategyConfigReader.java | 90 ++++++++++++ ...dEntityOwnershipServiceProviderModule.java | 11 +- ...OwnershipServiceProviderModuleFactory.java | 19 +++ ...wnerSelectionStrategyConfigReaderTest.java | 130 ++++++++++++++++++ 5 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReader.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReaderTest.java diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfig.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfig.java index db2377d4d5..298589ae05 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfig.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfig.java @@ -23,6 +23,10 @@ public class EntityOwnerSelectionStrategyConfig { } + public boolean isStrategyConfigured(String entityType){ + return entityTypeToStrategyInfo.get(entityType) != null; + } + public EntityOwnerSelectionStrategy createStrategy(String entityType){ final EntityOwnerSelectionStrategy strategy; final EntityOwnerSelectionStrategy existingStrategy = entityTypeToOwnerSelectionStrategy.get(entityType); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReader.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReader.java new file mode 100644 index 0000000000..b6092b2e00 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReader.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 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.controller.cluster.datastore.entityownership.selectionstrategy; + +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.util.Dictionary; +import java.util.Enumeration; +import javax.annotation.Nullable; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EntityOwnerSelectionStrategyConfigReader { + public static final String CONFIG_ID = "org.opendaylight.controller.cluster.entity-owner-selection-strategies"; + + private static final Logger LOG = LoggerFactory.getLogger(EntityOwnerSelectionStrategyConfigReader.class); + private final BundleContext bundleContext; + private final EntityOwnerSelectionStrategyConfig config; + + public EntityOwnerSelectionStrategyConfigReader(BundleContext bundleContext) { + this.bundleContext = Preconditions.checkNotNull(bundleContext); + ServiceReference configAdminServiceReference = + bundleContext.getServiceReference(ConfigurationAdmin.class); + if(configAdminServiceReference == null) { + LOG.warn("No ConfigurationAdmin service found"); + this.config = EntityOwnerSelectionStrategyConfig.newBuilder().build(); + } else { + this.config = readConfiguration(configAdminServiceReference); + } + } + + private EntityOwnerSelectionStrategyConfig readConfiguration(ServiceReference configAdminServiceReference) { + EntityOwnerSelectionStrategyConfig.Builder builder = EntityOwnerSelectionStrategyConfig.newBuilder(); + ConfigurationAdmin configAdmin = null; + try { + configAdmin = bundleContext.getService(configAdminServiceReference); + Dictionary properties = getProperties(configAdmin); + if(properties != null) { + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + String strategyProps = (String) properties.get(key); + String[] strategyClassAndDelay = strategyProps.split(","); + if(strategyClassAndDelay.length >= 1) { + @SuppressWarnings("unchecked") + Class aClass + = (Class) getClass().getClassLoader().loadClass(strategyClassAndDelay[0]); + long delay = 0; + if(strategyClassAndDelay.length > 1){ + delay = Long.parseLong(strategyClassAndDelay[1]); + } + builder.addStrategy(key, aClass, delay); + } + } + } + } catch(Exception e){ + LOG.warn("Failed to read selection strategy configuration file. All configuration will be ignored.", e); + } finally { + if(configAdmin != null) { + try { + bundleContext.ungetService(configAdminServiceReference); + } catch (Exception e) { + LOG.debug("Error from ungetService", e); + } + } + } + + return builder.build(); + } + + @Nullable + private static Dictionary getProperties(ConfigurationAdmin configAdmin) throws IOException { + Configuration config = configAdmin.getConfiguration(CONFIG_ID); + return config != null ? config.getProperties() : null; + } + + public EntityOwnerSelectionStrategyConfig getConfig() { + return config; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModule.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModule.java index 679f067afc..7a43bfd83e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModule.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModule.java @@ -4,10 +4,14 @@ import com.google.common.base.Preconditions; import org.opendaylight.controller.cluster.datastore.DistributedDataStore; import org.opendaylight.controller.cluster.datastore.entityownership.DistributedEntityOwnershipService; import org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.EntityOwnerSelectionStrategyConfig; +import org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.EntityOwnerSelectionStrategyConfigReader; import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.osgi.framework.BundleContext; public class DistributedEntityOwnershipServiceProviderModule extends org.opendaylight.controller.config.yang.config.distributed_entity_ownership_service.AbstractDistributedEntityOwnershipServiceProviderModule { + private BundleContext bundleContext; + public DistributedEntityOwnershipServiceProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } @@ -31,8 +35,13 @@ public class DistributedEntityOwnershipServiceProviderModule extends org.openday DOMStore dataStore = getDataStoreDependency(); Preconditions.checkArgument(dataStore instanceof DistributedDataStore, "Injected DOMStore must be an instance of DistributedDataStore"); - DistributedEntityOwnershipService service = new DistributedEntityOwnershipService((DistributedDataStore)dataStore, EntityOwnerSelectionStrategyConfig.newBuilder().build()); + EntityOwnerSelectionStrategyConfig strategyConfig = new EntityOwnerSelectionStrategyConfigReader(bundleContext).getConfig(); + DistributedEntityOwnershipService service = new DistributedEntityOwnershipService((DistributedDataStore)dataStore, strategyConfig); service.start(); return service; } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModuleFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModuleFactory.java index 7d7447d4b0..3eb6d9fc7d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModuleFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_entity_ownership_service/DistributedEntityOwnershipServiceProviderModuleFactory.java @@ -8,6 +8,25 @@ * Do not modify this file unless it is present under src/main directory */ package org.opendaylight.controller.config.yang.config.distributed_entity_ownership_service; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + public class DistributedEntityOwnershipServiceProviderModuleFactory extends org.opendaylight.controller.config.yang.config.distributed_entity_ownership_service.AbstractDistributedEntityOwnershipServiceProviderModuleFactory { + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + DistributedEntityOwnershipServiceProviderModule module = (DistributedEntityOwnershipServiceProviderModule) super.createModule(instanceName, dependencyResolver, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + DistributedEntityOwnershipServiceProviderModule module = (DistributedEntityOwnershipServiceProviderModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReaderTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReaderTest.java new file mode 100644 index 0000000000..252e7b7cb1 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/selectionstrategy/EntityOwnerSelectionStrategyConfigReaderTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 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.controller.cluster.datastore.entityownership.selectionstrategy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import java.io.IOException; +import java.util.Hashtable; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; + +public class EntityOwnerSelectionStrategyConfigReaderTest { + @Mock + private BundleContext mockBundleContext; + + @Mock + private ServiceReference mockConfigAdminServiceRef; + + @Mock + private ConfigurationAdmin mockConfigAdmin; + + @Mock + private Configuration mockConfig; + + @Before + public void setup() throws IOException { + MockitoAnnotations.initMocks(this); + + doReturn(mockConfigAdminServiceRef).when(mockBundleContext).getServiceReference(ConfigurationAdmin.class); + doReturn(mockConfigAdmin).when(mockBundleContext).getService(mockConfigAdminServiceRef); + + doReturn(mockConfig).when(mockConfigAdmin).getConfiguration(EntityOwnerSelectionStrategyConfigReader.CONFIG_ID); + } + + @Test + public void testReadStrategies(){ + Hashtable props = new Hashtable<>(); + props.put("test", "org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.LastCandidateSelectionStrategy,100"); + + doReturn(props).when(mockConfig).getProperties(); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertTrue(config.isStrategyConfigured("test")); + + EntityOwnerSelectionStrategy strategy = config.createStrategy("test"); + assertTrue(strategy instanceof LastCandidateSelectionStrategy); + assertEquals(100L, strategy.getSelectionDelayInMillis()); + } + + @Test + public void testReadStrategiesWithIOException() throws IOException { + doThrow(IOException.class).when(mockConfigAdmin).getConfiguration(EntityOwnerSelectionStrategyConfigReader.CONFIG_ID); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertFalse(config.isStrategyConfigured("test")); + } + + @Test + public void testReadStrategiesWithNullConfiguration() throws IOException { + doReturn(null).when(mockConfigAdmin).getConfiguration(EntityOwnerSelectionStrategyConfigReader.CONFIG_ID); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertFalse(config.isStrategyConfigured("test")); + } + + @Test + public void testReadStrategiesWithNullConfigurationProperties() throws IOException { + doReturn(null).when(mockConfig).getProperties(); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertFalse(config.isStrategyConfigured("test")); + } + + @Test + public void testReadStrategiesInvalidDelay(){ + Hashtable props = new Hashtable<>(); + props.put("test", "org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.LastCandidateSelectionStrategy,foo"); + + doReturn(props).when(mockConfig).getProperties(); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertFalse(config.isStrategyConfigured("test")); + } + + @Test + public void testReadStrategiesInvalidClassType(){ + Hashtable props = new Hashtable<>(); + props.put("test", "String,100"); + + doReturn(props).when(mockConfig).getProperties(); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertFalse(config.isStrategyConfigured("test")); + } + + @Test + public void testReadStrategiesMissingDelay(){ + Hashtable props = new Hashtable<>(); + props.put("test", "org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.LastCandidateSelectionStrategy,100"); + props.put("test1", "org.opendaylight.controller.cluster.datastore.entityownership.selectionstrategy.LastCandidateSelectionStrategy"); + + doReturn(props).when(mockConfig).getProperties(); + + EntityOwnerSelectionStrategyConfig config = new EntityOwnerSelectionStrategyConfigReader(mockBundleContext).getConfig(); + + assertEquals(100, config.createStrategy("test").getSelectionDelayInMillis()); + assertEquals(0, config.createStrategy("test2").getSelectionDelayInMillis()); + } + +} \ No newline at end of file -- 2.36.6