From f8b768f558e8f77509f1e37de6da382f821c8be0 Mon Sep 17 00:00:00 2001 From: Jakub Toth Date: Tue, 24 Oct 2017 15:54:46 +0200 Subject: [PATCH] Bug 9288 - DistributedDataStoreFactory in sal-distributed-datastore uses hardcoded dependencies on OSGI/karaf * remove config admin overlay in java * add managed-properties to specifc bean in blueprint for listening on config admin change in blueprint context and invkoking update method * fix tests Change-Id: I5bc33348bdb7f3317d02d956796d947859246e61 Signed-off-by: Jakub Toth --- .../cluster/datastore/AbstractDataStore.java | 2 +- .../DatastoreContextConfigAdminOverlay.java | 112 ----------- .../DatastoreContextIntrospector.java | 86 ++++---- .../DatastoreContextPropertiesUpdater.java | 59 ++++++ .../DistributedDataStoreFactory.java | 35 +--- .../blueprint/clustered-datastore.xml | 30 ++- ...atastoreContextConfigAdminOverlayTest.java | 184 ------------------ ...reContextContextPropertiesUpdaterTest.java | 105 ++++++++++ .../DatastoreContextIntrospectorTest.java | 25 +-- 9 files changed, 256 insertions(+), 382 deletions(-) delete mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlay.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextPropertiesUpdater.java delete mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlayTest.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextContextPropertiesUpdaterTest.java diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/AbstractDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/AbstractDataStore.java index 9fd50ee6c8..de6bc7e9f8 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/AbstractDataStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/AbstractDataStore.java @@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory; * Base implementation of a distributed DOMStore. */ public abstract class AbstractDataStore implements DistributedDataStoreInterface, SchemaContextListener, - DatastoreContextConfigAdminOverlay.Listener, DOMStoreTreeChangePublisher, + DatastoreContextPropertiesUpdater.Listener, DOMStoreTreeChangePublisher, DOMDataTreeCommitCohortRegistry, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(AbstractDataStore.class); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlay.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlay.java deleted file mode 100644 index 23fcf19ec2..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlay.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2015 Brocade Communications 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; - -import java.io.IOException; -import java.util.Dictionary; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.cm.Configuration; -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.cm.ConfigurationEvent; -import org.osgi.service.cm.ConfigurationListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class that overlays DatastoreContext settings with settings obtained from an OSGi Config Admin - * service. - * - * @author Thomas Pantelis - */ -public class DatastoreContextConfigAdminOverlay implements AutoCloseable { - public static final String CONFIG_ID = "org.opendaylight.controller.cluster.datastore"; - - public interface Listener { - void onDatastoreContextUpdated(DatastoreContextFactory contextFactory); - } - - private static final Logger LOG = LoggerFactory.getLogger(DatastoreContextConfigAdminOverlay.class); - - private final DatastoreContextIntrospector introspector; - private final BundleContext bundleContext; - private ServiceRegistration configListenerServiceRef; - private Listener listener; - - public DatastoreContextConfigAdminOverlay(DatastoreContextIntrospector introspector, - BundleContext bundleContext) { - this.introspector = introspector; - this.bundleContext = bundleContext; - - ServiceReference configAdminServiceReference = - bundleContext.getServiceReference(ConfigurationAdmin.class); - if (configAdminServiceReference == null) { - LOG.warn("No ConfigurationAdmin service found"); - } else { - overlaySettings(configAdminServiceReference); - - configListenerServiceRef = bundleContext.registerService(ConfigurationListener.class.getName(), - new DatastoreConfigurationListener(), null); - } - } - - public void setListener(Listener listener) { - this.listener = listener; - } - - @SuppressWarnings({"checkstyle:IllegalCatch", - "squid:S1166" /* Exception handlers should preserve the original exception */}) - private void overlaySettings(ServiceReference configAdminServiceReference) { - try { - ConfigurationAdmin configAdmin = bundleContext.getService(configAdminServiceReference); - - Configuration config = configAdmin.getConfiguration(CONFIG_ID); - if (config != null) { - Dictionary properties = config.getProperties(); - - LOG.debug("Overlaying settings: {}", properties); - - if (introspector.update(properties) && listener != null) { - listener.onDatastoreContextUpdated(introspector.newContextFactory()); - } - } else { - LOG.debug("No Configuration found for {}", CONFIG_ID); - } - } catch (IOException e) { - LOG.error("Error obtaining Configuration for pid {}", CONFIG_ID, e); - } catch (IllegalStateException e) { - // Ignore - indicates the bundleContext has been closed. - } finally { - try { - bundleContext.ungetService(configAdminServiceReference); - } catch (Exception e) { - LOG.debug("Error from ungetService", e); - } - } - } - - @Override - public void close() { - listener = null; - - if (configListenerServiceRef != null) { - configListenerServiceRef.unregister(); - } - } - - private class DatastoreConfigurationListener implements ConfigurationListener { - @Override - public void configurationEvent(ConfigurationEvent event) { - if (CONFIG_ID.equals(event.getPid()) && event.getType() == ConfigurationEvent.CM_UPDATED) { - LOG.debug("configurationEvent: config {} was updated", CONFIG_ID); - overlaySettings(event.getReference()); - } - } - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospector.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospector.java index aa54d5b9e1..aa93ecd549 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospector.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospector.java @@ -23,7 +23,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Dictionary; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,7 +56,7 @@ public class DatastoreContextIntrospector { introspectDatastoreContextBuilder(); introspectDataStoreProperties(); introspectPrimitiveTypes(); - } catch (IntrospectionException e) { + } catch (final IntrospectionException e) { LOG.error("Error initializing DatastoreContextIntrospector", e); } } @@ -70,12 +69,12 @@ public class DatastoreContextIntrospector { // Disables "Either log or rethrow this exception" sonar warning @SuppressWarnings("squid:S1166") private static void introspectPrimitiveTypes() { - Set> primitives = ImmutableSet.>builder().addAll( + final Set> primitives = ImmutableSet.>builder().addAll( Primitives.allWrapperTypes()).add(String.class).build(); - for (Class primitive: primitives) { + for (final Class primitive: primitives) { try { processPropertyType(primitive); - } catch (NoSuchMethodException e) { + } catch (final NoSuchMethodException e) { // Ignore primitives that can't be constructed from a String, eg Character and Void. } catch (SecurityException | IntrospectionException e) { LOG.error("Error introspect primitive type {}", primitive, e); @@ -90,7 +89,7 @@ public class DatastoreContextIntrospector { * the methods that return Builder. */ private static void introspectDatastoreContextBuilder() { - for (Method method: Builder.class.getMethods()) { + for (final Method method: Builder.class.getMethods()) { if (Builder.class.equals(method.getReturnType())) { BUILDER_SETTERS.put(method.getName(), method); } @@ -104,8 +103,8 @@ public class DatastoreContextIntrospector { * the appropriate constructor that we will use. */ private static void introspectDataStoreProperties() throws IntrospectionException { - BeanInfo beanInfo = Introspector.getBeanInfo(DataStoreProperties.class); - for (PropertyDescriptor desc: beanInfo.getPropertyDescriptors()) { + final BeanInfo beanInfo = Introspector.getBeanInfo(DataStoreProperties.class); + for (final PropertyDescriptor desc: beanInfo.getPropertyDescriptors()) { processDataStoreProperty(desc.getName(), desc.getPropertyType()); } @@ -113,10 +112,10 @@ public class DatastoreContextIntrospector { // properties and thus aren't returned from getPropertyDescriptors. A getter starting with // "is" is only supported if it returns primitive boolean. So we'll check for these via // getMethodDescriptors. - for (MethodDescriptor desc: beanInfo.getMethodDescriptors()) { - String methodName = desc.getName(); + for (final MethodDescriptor desc: beanInfo.getMethodDescriptors()) { + final String methodName = desc.getName(); if (Boolean.class.equals(desc.getMethod().getReturnType()) && methodName.startsWith("is")) { - String propertyName = WordUtils.uncapitalize(methodName.substring(2)); + final String propertyName = WordUtils.uncapitalize(methodName.substring(2)); processDataStoreProperty(propertyName, Boolean.class); } } @@ -126,14 +125,14 @@ public class DatastoreContextIntrospector { * Processes a property defined on the DataStoreProperties interface. */ @SuppressWarnings("checkstyle:IllegalCatch") - private static void processDataStoreProperty(String name, Class propertyType) { + private static void processDataStoreProperty(final String name, final Class propertyType) { Preconditions.checkArgument(BUILDER_SETTERS.containsKey(name), String.format( "DataStoreProperties property \"%s\" does not have corresponding setter in DatastoreContext.Builder", name)); try { processPropertyType(propertyType); DATA_STORE_PROP_TYPES.put(name, propertyType); - } catch (Exception e) { + } catch (final Exception e) { LOG.error("Error finding constructor for type {}", propertyType, e); } } @@ -142,9 +141,9 @@ public class DatastoreContextIntrospector { * Finds the appropriate constructor for the specified type that we will use to construct * instances. */ - private static void processPropertyType(Class propertyType) throws NoSuchMethodException, SecurityException, - IntrospectionException { - Class wrappedType = Primitives.wrap(propertyType); + private static void processPropertyType(final Class propertyType) + throws NoSuchMethodException, SecurityException, IntrospectionException { + final Class wrappedType = Primitives.wrap(propertyType); if (CONSTRUCTORS.containsKey(wrappedType)) { return; } @@ -159,8 +158,8 @@ public class DatastoreContextIntrospector { // primitive as the only argument. This will be used to construct instances to perform // validation (eg range checking). The yang-generated types have a couple single-argument // constructors but the one we want has the bean ConstructorProperties annotation. - for (Constructor ctor: propertyType.getConstructors()) { - ConstructorProperties ctorPropsAnnotation = ctor.getAnnotation(ConstructorProperties.class); + for (final Constructor ctor: propertyType.getConstructors()) { + final ConstructorProperties ctorPropsAnnotation = ctor.getAnnotation(ConstructorProperties.class); if (ctor.getParameterTypes().length == 1 && ctorPropsAnnotation != null) { findYangTypeGetter(propertyType, ctorPropsAnnotation.value()[0]); CONSTRUCTORS.put(propertyType, ctor); @@ -173,8 +172,9 @@ public class DatastoreContextIntrospector { /** * Finds the getter method on a yang-generated type for the specified property name. */ - private static void findYangTypeGetter(Class type, String propertyName) throws IntrospectionException { - for (PropertyDescriptor desc: Introspector.getBeanInfo(type).getPropertyDescriptors()) { + private static void findYangTypeGetter(final Class type, final String propertyName) + throws IntrospectionException { + for (final PropertyDescriptor desc: Introspector.getBeanInfo(type).getPropertyDescriptors()) { if (desc.getName().equals(propertyName)) { YANG_TYPE_GETTERS.put(type, desc.getReadMethod()); return; @@ -191,7 +191,7 @@ public class DatastoreContextIntrospector { @GuardedBy(value = "this") private Map currentProperties; - public DatastoreContextIntrospector(DatastoreContext context) { + public DatastoreContextIntrospector(final DatastoreContext context) { this.context = context; } @@ -203,19 +203,19 @@ public class DatastoreContextIntrospector { return new DatastoreContextFactory(this); } - public synchronized DatastoreContext getShardDatastoreContext(String forShardName) { + public synchronized DatastoreContext getShardDatastoreContext(final String forShardName) { if (currentProperties == null) { return context; } - Builder builder = DatastoreContext.newBuilderFrom(context); - String dataStoreTypePrefix = context.getDataStoreName() + '.'; + final Builder builder = DatastoreContext.newBuilderFrom(context); + final String dataStoreTypePrefix = context.getDataStoreName() + '.'; final String shardNamePrefix = forShardName + '.'; - List keys = getSortedKeysByDatastoreType(currentProperties.keySet(), dataStoreTypePrefix); + final List keys = getSortedKeysByDatastoreType(currentProperties.keySet(), dataStoreTypePrefix); for (String key: keys) { - Object value = currentProperties.get(key); + final Object value = currentProperties.get(key); if (key.startsWith(dataStoreTypePrefix)) { key = key.replaceFirst(dataStoreTypePrefix, ""); } @@ -236,7 +236,7 @@ public class DatastoreContextIntrospector { * @param properties the properties to apply * @return true if the cached DatastoreContext was updated, false otherwise. */ - public synchronized boolean update(Dictionary properties) { + public synchronized boolean update(final Map properties) { currentProperties = null; if (properties == null || properties.isEmpty()) { return false; @@ -244,17 +244,17 @@ public class DatastoreContextIntrospector { LOG.debug("In update: properties: {}", properties); - ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); + final ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); - Builder builder = DatastoreContext.newBuilderFrom(context); + final Builder builder = DatastoreContext.newBuilderFrom(context); final String dataStoreTypePrefix = context.getDataStoreName() + '.'; - List keys = getSortedKeysByDatastoreType(Collections.list(properties.keys()), dataStoreTypePrefix); + final List keys = getSortedKeysByDatastoreType(properties.keySet(), dataStoreTypePrefix); boolean updated = false; for (String key: keys) { - Object value = properties.get(key); + final Object value = properties.get(key); mapBuilder.put(key, value); // If the key is prefixed with the data store type, strip it off. @@ -276,23 +276,23 @@ public class DatastoreContextIntrospector { return updated; } - private static ArrayList getSortedKeysByDatastoreType(Collection inKeys, + private static ArrayList getSortedKeysByDatastoreType(final Collection inKeys, final String dataStoreTypePrefix) { // Sort the property keys by putting the names prefixed with the data store type last. This // is done so data store specific settings are applied after global settings. - ArrayList keys = new ArrayList<>(inKeys); + final ArrayList keys = new ArrayList<>(inKeys); Collections.sort(keys, (key1, key2) -> key1.startsWith(dataStoreTypePrefix) ? 1 : key2.startsWith(dataStoreTypePrefix) ? -1 : key1.compareTo(key2)); return keys; } @SuppressWarnings("checkstyle:IllegalCatch") - private boolean convertValueAndInvokeSetter(String inKey, Object inValue, Builder builder) { - String key = convertToCamelCase(inKey); + private boolean convertValueAndInvokeSetter(final String inKey, final Object inValue, final Builder builder) { + final String key = convertToCamelCase(inKey); try { // Convert the value to the right type. - Object value = convertValue(key, inValue); + final Object value = convertValue(key, inValue); if (value == null) { return false; } @@ -301,7 +301,7 @@ public class DatastoreContextIntrospector { key, value, value.getClass().getSimpleName()); // Call the setter method on the Builder instance. - Method setter = BUILDER_SETTERS.get(key); + final Method setter = BUILDER_SETTERS.get(key); setter.invoke(builder, constructorValueRecursively( Primitives.wrap(setter.getParameterTypes()[0]), value.toString())); @@ -314,7 +314,7 @@ public class DatastoreContextIntrospector { return false; } - private static String convertToCamelCase(String inString) { + private static String convertToCamelCase(final String inString) { String str = inString.trim(); if (StringUtils.contains(str, '-') || StringUtils.contains(str, ' ')) { str = inString.replace('-', ' '); @@ -325,9 +325,9 @@ public class DatastoreContextIntrospector { return StringUtils.uncapitalize(str); } - private Object convertValue(String name, Object from) + private Object convertValue(final String name, final Object from) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { - Class propertyType = DATA_STORE_PROP_TYPES.get(name); + final Class propertyType = DATA_STORE_PROP_TYPES.get(name); if (propertyType == null) { LOG.debug("Property not found for {}", name); return null; @@ -342,7 +342,7 @@ public class DatastoreContextIntrospector { Object converted = constructorValueRecursively(propertyType, from.toString()); // If the converted type is a yang-generated type, call the getter to obtain the actual value. - Method getter = YANG_TYPE_GETTERS.get(converted.getClass()); + final Method getter = YANG_TYPE_GETTERS.get(converted.getClass()); if (getter != null) { converted = getter.invoke(converted); } @@ -350,12 +350,12 @@ public class DatastoreContextIntrospector { return converted; } - private Object constructorValueRecursively(Class toType, Object fromValue) + private Object constructorValueRecursively(final Class toType, final Object fromValue) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { LOG.trace("convertValueRecursively - toType: {}, fromValue {} ({})", toType.getSimpleName(), fromValue, fromValue.getClass().getSimpleName()); - Constructor ctor = CONSTRUCTORS.get(toType); + final Constructor ctor = CONSTRUCTORS.get(toType); LOG.trace("Found {}", ctor); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextPropertiesUpdater.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextPropertiesUpdater.java new file mode 100644 index 0000000000..7dc01fc843 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextPropertiesUpdater.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Update DatastoreContext settings on invoke update method. + * + */ +public class DatastoreContextPropertiesUpdater implements AutoCloseable { + + public interface Listener { + void onDatastoreContextUpdated(DatastoreContextFactory contextFactory); + } + + private static final Logger LOG = LoggerFactory.getLogger(DatastoreContextPropertiesUpdater.class); + + private final DatastoreContextIntrospector introspector; + private Listener listener; + + /** + * Base init of updater for DatastoreContext settings with base properties. + * + * @param introspector + * - introspection on DatastoreContext + * @param props + * - base properties + */ + public DatastoreContextPropertiesUpdater(final DatastoreContextIntrospector introspector, + final Map props) { + this.introspector = introspector; + update(props); + } + + public void setListener(final Listener listener) { + this.listener = listener; + } + + public void update(final Map properties) { + LOG.debug("Overlaying settings: {}", properties); + + if (introspector.update(properties) && listener != null) { + listener.onDatastoreContextUpdated(introspector.newContextFactory()); + } + } + + @Override + public void close() { + listener = null; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java index a4256a77c8..2f82ac5d64 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java @@ -13,13 +13,12 @@ import org.opendaylight.controller.cluster.databroker.ClientBackedDataStore; import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl; import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot; -import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DistributedDataStoreFactory { + private static final Logger LOG = LoggerFactory.getLogger(DistributedDataStoreFactory.class); private static final String DEFAULT_MODULE_SHARDS_PATH = "./configuration/initial/module-shards.conf"; private static final String DEFAULT_MODULES_PATH = "./configuration/initial/modules.conf"; @@ -27,41 +26,24 @@ public class DistributedDataStoreFactory { private DistributedDataStoreFactory() { } - /** - * Create a data store instance. - * - * @deprecated Use {@link #createInstance(DOMSchemaService, DatastoreContext, DatastoreSnapshotRestore, - * ActorSystemProvider, BundleContext)} instead. - */ - @Deprecated - public static AbstractDataStore createInstance(final SchemaService schemaService, - final DatastoreContext initialDatastoreContext, final DatastoreSnapshotRestore datastoreSnapshotRestore, - final ActorSystemProvider actorSystemProvider, final BundleContext bundleContext) { - - return createInstance(schemaService, initialDatastoreContext, datastoreSnapshotRestore, - actorSystemProvider, bundleContext, null); - } - public static AbstractDataStore createInstance(final DOMSchemaService schemaService, final DatastoreContext initialDatastoreContext, final DatastoreSnapshotRestore datastoreSnapshotRestore, - final ActorSystemProvider actorSystemProvider, final BundleContext bundleContext) { + final ActorSystemProvider actorSystemProvider, final DatastoreContextIntrospector introspector, + final DatastoreContextPropertiesUpdater updater) { return createInstance(schemaService, initialDatastoreContext, datastoreSnapshotRestore, actorSystemProvider, - bundleContext, null); + introspector, updater, null); } public static AbstractDataStore createInstance(final DOMSchemaService schemaService, final DatastoreContext initialDatastoreContext, final DatastoreSnapshotRestore datastoreSnapshotRestore, - final ActorSystemProvider actorSystemProvider, final BundleContext bundleContext, - final Configuration orgConfig) { + final ActorSystemProvider actorSystemProvider, final DatastoreContextIntrospector introspector, + final DatastoreContextPropertiesUpdater updater, final Configuration orgConfig) { final String datastoreName = initialDatastoreContext.getDataStoreName(); LOG.info("Create data store instance of type : {}", datastoreName); final ActorSystem actorSystem = actorSystemProvider.getActorSystem(); final DatastoreSnapshot restoreFromSnapshot = datastoreSnapshotRestore.getAndRemove(datastoreName); - final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(initialDatastoreContext); - final DatastoreContextConfigAdminOverlay overlay = new DatastoreContextConfigAdminOverlay( - introspector, bundleContext); Configuration config; if (orgConfig == null) { @@ -85,12 +67,11 @@ public class DistributedDataStoreFactory { restoreFromSnapshot); LOG.info("Data store {} is using ask-based protocol", datastoreName); } - - overlay.setListener(dataStore); + updater.setListener(dataStore); schemaService.registerSchemaContextListener(dataStore); - dataStore.setCloseable(overlay); + dataStore.setCloseable(updater); dataStore.waitTillReady(); return dataStore; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/org/opendaylight/blueprint/clustered-datastore.xml b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/org/opendaylight/blueprint/clustered-datastore.xml index 90e26d9458..4bc117a5c7 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/org/opendaylight/blueprint/clustered-datastore.xml +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/org/opendaylight/blueprint/clustered-datastore.xml @@ -39,8 +39,10 @@ - + + + @@ -49,13 +51,24 @@ + + + + + + + + + + - + + @@ -77,13 +90,24 @@ + + + + + + + + + + - + + diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlayTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlayTest.java deleted file mode 100644 index d694cb668c..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlayTest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2015 Brocade Communications 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; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.IOException; -import java.util.Dictionary; -import java.util.Hashtable; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.cm.Configuration; -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.cm.ConfigurationEvent; -import org.osgi.service.cm.ConfigurationListener; - -/** - * Unit tests for DatastoreContextConfigAdminOverlay. - * - * @author Thomas Pantelis - */ -@SuppressWarnings("unchecked") -public class DatastoreContextConfigAdminOverlayTest { - - @Mock - private BundleContext mockBundleContext; - - @Mock - private ServiceReference mockConfigAdminServiceRef; - - @Mock - private ConfigurationAdmin mockConfigAdmin; - - @Mock - private Configuration mockConfig; - - @Mock - private DatastoreContextIntrospector mockIntrospector; - - @Mock - private ServiceRegistration configListenerServiceReg; - - @Before - public void setup() throws IOException { - MockitoAnnotations.initMocks(this); - - doReturn(mockConfigAdminServiceRef).when(mockBundleContext).getServiceReference(ConfigurationAdmin.class); - doReturn(mockConfigAdmin).when(mockBundleContext).getService(mockConfigAdminServiceRef); - doReturn(configListenerServiceReg).when(mockBundleContext).registerService( - eq(ConfigurationListener.class.getName()), any(), any(Dictionary.class)); - - doReturn(mockConfig).when(mockConfigAdmin).getConfiguration(DatastoreContextConfigAdminOverlay.CONFIG_ID); - - doReturn(DatastoreContextConfigAdminOverlay.CONFIG_ID).when(mockConfig).getPid(); - - } - - @Test - public void testUpdateOnConstruction() { - Dictionary properties = new Hashtable<>(); - properties.put("property", "value"); - doReturn(properties).when(mockConfig).getProperties(); - - DatastoreContextConfigAdminOverlay overlay = new DatastoreContextConfigAdminOverlay( - mockIntrospector, mockBundleContext); - - verify(mockIntrospector).update(properties); - - verify(mockBundleContext).ungetService(mockConfigAdminServiceRef); - - overlay.close(); - } - - @Test - public void testUpdateOnConfigurationEvent() { - final DatastoreContextConfigAdminOverlay overlay = new DatastoreContextConfigAdminOverlay( - mockIntrospector, mockBundleContext); - - reset(mockIntrospector); - - DatastoreContext context = DatastoreContext.newBuilder().build(); - doReturn(context).when(mockIntrospector).getContext(); - DatastoreContextFactory contextFactory = new DatastoreContextFactory(mockIntrospector); - doReturn(contextFactory).when(mockIntrospector).newContextFactory(); - - DatastoreContextConfigAdminOverlay.Listener mockListener = - mock(DatastoreContextConfigAdminOverlay.Listener.class); - - overlay.setListener(mockListener); - - Dictionary properties = new Hashtable<>(); - properties.put("property", "value"); - doReturn(properties).when(mockConfig).getProperties(); - - doReturn(true).when(mockIntrospector).update(properties); - - ArgumentCaptor configListener = - ArgumentCaptor.forClass(ConfigurationListener.class); - verify(mockBundleContext).registerService(eq(ConfigurationListener.class.getName()), - configListener.capture(), any(Dictionary.class)); - - ConfigurationEvent configEvent = mock(ConfigurationEvent.class); - doReturn(DatastoreContextConfigAdminOverlay.CONFIG_ID).when(configEvent).getPid(); - doReturn(mockConfigAdminServiceRef).when(configEvent).getReference(); - doReturn(ConfigurationEvent.CM_UPDATED).when(configEvent).getType(); - - configListener.getValue().configurationEvent(configEvent); - - verify(mockIntrospector).update(properties); - - verify(mockListener).onDatastoreContextUpdated(contextFactory); - - verify(mockBundleContext, times(2)).ungetService(mockConfigAdminServiceRef); - - overlay.close(); - - verify(configListenerServiceReg).unregister(); - } - - @Test - public void testConfigurationEventWithDifferentPid() { - final DatastoreContextConfigAdminOverlay overlay = new DatastoreContextConfigAdminOverlay( - mockIntrospector, mockBundleContext); - - reset(mockIntrospector); - - ArgumentCaptor configListener = - ArgumentCaptor.forClass(ConfigurationListener.class); - verify(mockBundleContext).registerService(eq(ConfigurationListener.class.getName()), - configListener.capture(), any(Dictionary.class)); - - ConfigurationEvent configEvent = mock(ConfigurationEvent.class); - doReturn("other-pid").when(configEvent).getPid(); - doReturn(mockConfigAdminServiceRef).when(configEvent).getReference(); - doReturn(ConfigurationEvent.CM_UPDATED).when(configEvent).getType(); - - configListener.getValue().configurationEvent(configEvent); - - verify(mockIntrospector, times(0)).update(any(Dictionary.class)); - - overlay.close(); - } - - @Test - public void testConfigurationEventWithNonUpdateEventType() { - final DatastoreContextConfigAdminOverlay overlay = new DatastoreContextConfigAdminOverlay( - mockIntrospector, mockBundleContext); - - reset(mockIntrospector); - - ArgumentCaptor configListener = - ArgumentCaptor.forClass(ConfigurationListener.class); - verify(mockBundleContext).registerService(eq(ConfigurationListener.class.getName()), - configListener.capture(), any(Dictionary.class)); - - ConfigurationEvent configEvent = mock(ConfigurationEvent.class); - doReturn(DatastoreContextConfigAdminOverlay.CONFIG_ID).when(configEvent).getPid(); - doReturn(mockConfigAdminServiceRef).when(configEvent).getReference(); - doReturn(ConfigurationEvent.CM_DELETED).when(configEvent).getType(); - - configListener.getValue().configurationEvent(configEvent); - - verify(mockIntrospector, times(0)).update(any(Dictionary.class)); - - overlay.close(); - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextContextPropertiesUpdaterTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextContextPropertiesUpdaterTest.java new file mode 100644 index 0000000000..88d1b8061f --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextContextPropertiesUpdaterTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.DatastoreContextPropertiesUpdater.Listener; + +public class DatastoreContextContextPropertiesUpdaterTest { + + @SuppressWarnings("unchecked") + @Test + public void updateOnConstructionTest() throws Exception { + final Map properties = new HashMap<>(); + properties.put("shardTransactionIdleTimeoutInMinutes", 10); + final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); + + final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(datastoreContext); + + final DatastoreContextPropertiesUpdater updater = new DatastoreContextPropertiesUpdater(introspector, + properties); + assertNotNull(updater); + + final Map props = (Map) resolveField("currentProperties", introspector); + + assertEquals(props.get("shardTransactionIdleTimeoutInMinutes"), 10); + } + + @SuppressWarnings("unchecked") + @Test + public void onUpdateTest() throws Exception { + final Map properties = new HashMap<>(); + properties.put("shardTransactionIdleTimeoutInMinutes", 10); + final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); + assertNotNull(datastoreContext); + final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(datastoreContext); + assertNotNull(introspector); + final DatastoreContextPropertiesUpdater updater = new DatastoreContextPropertiesUpdater(introspector, + properties); + assertNotNull(updater); + + Map props = (Map) resolveField("currentProperties", introspector); + assertTrue(!props.isEmpty()); + + properties.put("shardTransactionIdleTimeoutInMinutes", 20); + updater.update(properties); + + props = (Map) resolveField("currentProperties", introspector); + assertEquals(props.get("shardTransactionIdleTimeoutInMinutes"), 20); + } + + @SuppressWarnings("resource") + @Test + public void listenerTest() { + final Map properties = new HashMap<>(); + properties.put("shardTransactionIdleTimeoutInMinutes", 10); + + final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); + final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(datastoreContext); + final DatastoreContextPropertiesUpdater updater = new DatastoreContextPropertiesUpdater(introspector, + properties); + final DummyListenerImpl dummyListener = new DummyListenerImpl(); + updater.setListener(dummyListener); + + assertTrue(dummyListener.getContextFactory() == null); + updater.setListener(dummyListener); + properties.put("shardTransactionIdleTimeoutInMinutes", 20); + updater.update(properties); + + final DatastoreContextFactory contextFactory = dummyListener.getContextFactory(); + assertNotNull(contextFactory); + updater.close(); + } + + private Object resolveField(final String name, final Object obj) throws Exception { + final Field currProps = obj.getClass().getDeclaredField(name); + currProps.setAccessible(true); + return currProps.get(obj); + } + + private class DummyListenerImpl implements Listener { + + private DatastoreContextFactory contextFactory; + + @Override + public void onDatastoreContextUpdated(final DatastoreContextFactory contextFactory) { + this.contextFactory = contextFactory; + } + + public DatastoreContextFactory getContextFactory() { + return contextFactory; + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospectorTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospectorTest.java index e397d1bb4e..b9d6f46185 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospectorTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospectorTest.java @@ -15,8 +15,9 @@ import static org.opendaylight.controller.cluster.datastore.DatastoreContext.DEF import static org.opendaylight.controller.cluster.datastore.DatastoreContext.DEFAULT_SHARD_TRANSACTION_IDLE_TIMEOUT; import static org.opendaylight.controller.cluster.datastore.DatastoreContext.DEFAULT_SHARD_TX_COMMIT_TIMEOUT_IN_SECONDS; -import java.util.Dictionary; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties; @@ -32,9 +33,9 @@ public class DatastoreContextIntrospectorTest { public void testUpdate() { DatastoreContext context = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.OPERATIONAL).build(); - DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(context); + final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(context); - Dictionary properties = new Hashtable<>(); + final Map properties = new HashMap<>(); properties.put("shard-transaction-idle-timeout-in-minutes", "31"); properties.put("operation-timeout-in-seconds", "26"); properties.put("shard-transaction-commit-timeout-in-seconds", "100"); @@ -122,9 +123,9 @@ public class DatastoreContextIntrospectorTest { public void testUpdateWithInvalidValues() { DatastoreContext context = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.OPERATIONAL).build(); - DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(context); + final DatastoreContextIntrospector introspector = new DatastoreContextIntrospector(context); - Dictionary properties = new Hashtable<>(); + final Map properties = new HashMap<>(); properties.put("shard-transaction-idle-timeout-in-minutes", "0"); // bad - must be > 0 properties.put("shard-journal-recovery-log-batch-size", "199"); properties.put("shard-transaction-commit-timeout-in-seconds", "bogus"); // bad - NaN @@ -137,7 +138,7 @@ public class DatastoreContextIntrospectorTest { properties.put("max-shard-data-change-executor-pool-size", "bogus"); // bad - NaN properties.put("unknownProperty", "1"); // bad - invalid property name - boolean updated = introspector.update(properties); + final boolean updated = introspector.update(properties); assertEquals("updated", true, updated); context = introspector.getContext(); @@ -158,7 +159,7 @@ public class DatastoreContextIntrospectorTest { @Test public void testUpdateWithDatastoreTypeSpecificProperties() { - Dictionary properties = new Hashtable<>(); + final Map properties = new HashMap<>(); properties.put("shard-transaction-idle-timeout-in-minutes", "22"); // global setting properties.put("operational.shard-transaction-idle-timeout-in-minutes", "33"); // operational override properties.put("config.shard-transaction-idle-timeout-in-minutes", "44"); // config override @@ -172,7 +173,7 @@ public class DatastoreContextIntrospectorTest { DatastoreContext operContext = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.OPERATIONAL).build(); - DatastoreContextIntrospector operIntrospector = new DatastoreContextIntrospector(operContext); + final DatastoreContextIntrospector operIntrospector = new DatastoreContextIntrospector(operContext); boolean updated = operIntrospector.update(properties); assertEquals("updated", true, updated); operContext = operIntrospector.getContext(); @@ -183,7 +184,7 @@ public class DatastoreContextIntrospectorTest { DatastoreContext configContext = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.CONFIGURATION).build(); - DatastoreContextIntrospector configIntrospector = new DatastoreContextIntrospector(configContext); + final DatastoreContextIntrospector configIntrospector = new DatastoreContextIntrospector(configContext); updated = configIntrospector.update(properties); assertEquals("updated", true, updated); configContext = configIntrospector.getContext(); @@ -195,7 +196,7 @@ public class DatastoreContextIntrospectorTest { @Test public void testGetDatastoreContextForShard() { - Dictionary properties = new Hashtable<>(); + final Map properties = new HashMap<>(); properties.put("shard-transaction-idle-timeout-in-minutes", "22"); // global setting properties.put("operational.shard-transaction-idle-timeout-in-minutes", "33"); // operational override properties.put("config.shard-transaction-idle-timeout-in-minutes", "44"); // config override @@ -203,7 +204,7 @@ public class DatastoreContextIntrospectorTest { DatastoreContext operContext = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.OPERATIONAL).build(); - DatastoreContextIntrospector operIntrospector = new DatastoreContextIntrospector(operContext); + final DatastoreContextIntrospector operIntrospector = new DatastoreContextIntrospector(operContext); DatastoreContext shardContext = operIntrospector.newContextFactory().getShardDatastoreContext("topology"); assertEquals(10, shardContext.getShardTransactionIdleTimeout().toMinutes()); @@ -217,7 +218,7 @@ public class DatastoreContextIntrospectorTest { DatastoreContext configContext = DatastoreContext.newBuilder() .logicalStoreType(LogicalDatastoreType.CONFIGURATION).build(); - DatastoreContextIntrospector configIntrospector = new DatastoreContextIntrospector(configContext); + final DatastoreContextIntrospector configIntrospector = new DatastoreContextIntrospector(configContext); configIntrospector.update(properties); configContext = configIntrospector.getContext(); assertEquals(44, configContext.getShardTransactionIdleTimeout().toMinutes()); -- 2.36.6