Bug 9288 - DistributedDataStoreFactory in sal-distributed-datastore 62/64662/10
authorJakub Toth <jakub.toth@pantheon.tech>
Tue, 24 Oct 2017 13:54:46 +0000 (15:54 +0200)
committerJakub Toth <jakub.toth@pantheon.tech>
Wed, 25 Oct 2017 21:46:31 +0000 (23:46 +0200)
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 <jakub.toth@pantheon.tech>
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/AbstractDataStore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlay.java [deleted file]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospector.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContextPropertiesUpdater.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/resources/org/opendaylight/blueprint/clustered-datastore.xml
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextConfigAdminOverlayTest.java [deleted file]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextContextPropertiesUpdaterTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextIntrospectorTest.java

index 9fd50ee..de6bc7e 100644 (file)
@@ -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 (file)
index 23fcf19..0000000
+++ /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<ConfigurationAdmin> 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<ConfigurationAdmin> configAdminServiceReference) {
-        try {
-            ConfigurationAdmin configAdmin = bundleContext.getService(configAdminServiceReference);
-
-            Configuration config = configAdmin.getConfiguration(CONFIG_ID);
-            if (config != null) {
-                Dictionary<String, Object> 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());
-            }
-        }
-    }
-}
index aa54d5b..aa93ecd 100644 (file)
@@ -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<Class<?>> primitives = ImmutableSet.<Class<?>>builder().addAll(
+        final Set<Class<?>> primitives = ImmutableSet.<Class<?>>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<String, Object> 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<String> keys = getSortedKeysByDatastoreType(currentProperties.keySet(), dataStoreTypePrefix);
+        final List<String> 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<String, Object> properties) {
+    public synchronized boolean update(final Map<String, Object> 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<String, Object> mapBuilder = ImmutableMap.<String, Object>builder();
+        final ImmutableMap.Builder<String, Object> mapBuilder = ImmutableMap.<String, Object>builder();
 
-        Builder builder = DatastoreContext.newBuilderFrom(context);
+        final Builder builder = DatastoreContext.newBuilderFrom(context);
 
         final String dataStoreTypePrefix = context.getDataStoreName() + '.';
 
-        List<String> keys = getSortedKeysByDatastoreType(Collections.list(properties.keys()), dataStoreTypePrefix);
+        final List<String> 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<String> getSortedKeysByDatastoreType(Collection<String> inKeys,
+    private static ArrayList<String> getSortedKeysByDatastoreType(final Collection<String> 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<String> keys = new ArrayList<>(inKeys);
+        final ArrayList<String> 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 (file)
index 0000000..7dc01fc
--- /dev/null
@@ -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<String, Object> props) {
+        this.introspector = introspector;
+        update(props);
+    }
+
+    public void setListener(final Listener listener) {
+        this.listener = listener;
+    }
+
+    public void update(final Map<String, Object> properties) {
+        LOG.debug("Overlaying settings: {}", properties);
+
+        if (introspector.update(properties) && listener != null) {
+            listener.onDatastoreContextUpdated(introspector.newContextFactory());
+        }
+    }
+
+    @Override
+    public void close() {
+        listener = null;
+    }
+}
index a4256a7..2f82ac5 100644 (file)
@@ -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;
index 90e26d9..4bc117a 100644 (file)
 
   <service ref="actorSystemProvider" interface="org.opendaylight.controller.cluster.ActorSystemProvider"/>
 
-  <!-- Distributed Config Datastore -->
+  <!-- Datastore properties -->
+  <cm:cm-properties id="datastoreProps" persistent-id="org.opendaylight.controller.cluster.datastore"/>
 
+  <!-- Distributed Config Datastore -->
   <bean id="datastoreSnapshotRestore" class="org.opendaylight.controller.cluster.datastore.DatastoreSnapshotRestore"
           factory-method="instance">
     <argument value="./clustered-datastore-restore"/>
   <bean id="configDatastoreContext" class="org.opendaylight.controller.config.yang.config.distributed_datastore_provider.DistributedConfigDataStoreProviderModule"
           factory-method="newDatastoreContext" />
 
+  <bean id="introspectorConfig" class="org.opendaylight.controller.cluster.datastore.DatastoreContextIntrospector">
+    <argument ref="configDatastoreContext"/>
+  </bean>
+
+  <bean id="updaterConfig" class="org.opendaylight.controller.cluster.datastore.DatastoreContextPropertiesUpdater">
+    <cm:managed-properties persistent-id="org.opendaylight.controller.cluster.datastore" update-strategy="component-managed" update-method="update"/>
+    <argument ref="introspectorConfig"/>
+    <argument ref="datastoreProps"/>
+  </bean>
+
   <bean id="configDatastore" class="org.opendaylight.controller.cluster.datastore.DistributedDataStoreFactory"
           factory-method="createInstance" destroy-method="close">
     <argument ref="schemaService"/>
     <argument ref="configDatastoreContext"/>
     <argument ref="datastoreSnapshotRestore"/>
     <argument ref="actorSystemProvider"/>
-    <argument ref="blueprintBundleContext"/>
+    <argument ref="introspectorConfig"/>
+    <argument ref="updaterConfig"/>
   </bean>
 
   <service ref="configDatastore" odl:type="distributed-config">
   <bean id="operDatastoreContext" class="org.opendaylight.controller.config.yang.config.distributed_datastore_provider.DistributedOperationalDataStoreProviderModule"
           factory-method="newDatastoreContext" />
 
+  <bean id="introspectorOper" class="org.opendaylight.controller.cluster.datastore.DatastoreContextIntrospector">
+    <argument ref="operDatastoreContext"/>
+  </bean>
+
+  <bean id="updaterOper" class="org.opendaylight.controller.cluster.datastore.DatastoreContextPropertiesUpdater">
+    <cm:managed-properties persistent-id="org.opendaylight.controller.cluster.datastore" update-strategy="component-managed" update-method="update"/>
+    <argument ref="introspectorOper"/>
+    <argument ref="datastoreProps"/>
+  </bean>
+
   <bean id="operDatastore" class="org.opendaylight.controller.cluster.datastore.DistributedDataStoreFactory"
           factory-method="createInstance" destroy-method="close">
     <argument ref="schemaService"/>
     <argument ref="operDatastoreContext"/>
     <argument ref="datastoreSnapshotRestore"/>
     <argument ref="actorSystemProvider"/>
-    <argument ref="blueprintBundleContext"/>
+    <argument ref="introspectorOper"/>
+    <argument ref="updaterOper"/>
     <argument ref="configurationImpl" />
   </bean>
 
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 (file)
index d694cb6..0000000
+++ /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<ConfigurationAdmin> 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<String, Object> 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<String, Object> properties = new Hashtable<>();
-        properties.put("property", "value");
-        doReturn(properties).when(mockConfig).getProperties();
-
-        doReturn(true).when(mockIntrospector).update(properties);
-
-        ArgumentCaptor<ConfigurationListener> 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<ConfigurationListener> 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<ConfigurationListener> 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 (file)
index 0000000..88d1b80
--- /dev/null
@@ -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<String, Object> 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<String, Object> props = (Map<String, Object>) resolveField("currentProperties", introspector);
+
+        assertEquals(props.get("shardTransactionIdleTimeoutInMinutes"), 10);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void onUpdateTest() throws Exception {
+        final Map<String, Object> 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<String, Object> props = (Map<String, Object>) resolveField("currentProperties", introspector);
+        assertTrue(!props.isEmpty());
+
+        properties.put("shardTransactionIdleTimeoutInMinutes", 20);
+        updater.update(properties);
+
+        props = (Map<String, Object>) resolveField("currentProperties", introspector);
+        assertEquals(props.get("shardTransactionIdleTimeoutInMinutes"), 20);
+    }
+
+    @SuppressWarnings("resource")
+    @Test
+    public void listenerTest() {
+        final Map<String, Object> 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;
+        }
+    }
+}
index e397d1b..b9d6f46 100644 (file)
@@ -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<String, Object> properties = new Hashtable<>();
+        final Map<String, Object> 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<String, Object> properties = new Hashtable<>();
+        final Map<String, Object> 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<String, Object> properties = new Hashtable<>();
+        final Map<String, Object> 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<String, Object> properties = new Hashtable<>();
+        final Map<String, Object> 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());

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.