You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2016/09/05 12:19:33 UTC

svn commit: r1759245 - in /aries/trunk/blueprint: blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/

Author: gnodet
Date: Mon Sep  5 12:19:33 2016
New Revision: 1759245

URL: http://svn.apache.org/viewvc?rev=1759245&view=rev
Log:
[ARIES-1578] blueprint-cm doesn't support org.osgi.service.cm.ConfigurationPlugin

Modified:
    aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java
    aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java
    aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java
    aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java
    aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java
    aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/TestConfigAdmin.java

Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java Mon Sep  5 12:19:33 2016
@@ -65,6 +65,7 @@ public class CmManagedProperties impleme
     private final Object lock = new Object();
     private final Set<Object> beans = new HashSet<Object>();
     private Dictionary<String,Object> properties;
+    private boolean initialized;
 
     public ExtendedBlueprintContainer getBlueprintContainer() {
         return blueprintContainer;
@@ -137,11 +138,6 @@ public class CmManagedProperties impleme
                 
         synchronized (lock) {
             managedObjectManager.register(this, props);
-            Configuration config = CmUtils.getConfiguration(configAdmin, persistentId);
-            if (config != null) {
-                properties = config.getProperties();
-            }
-            updated(properties);
         }
     }
 
@@ -150,6 +146,11 @@ public class CmManagedProperties impleme
     }
 
     public void updated(final Dictionary props) {
+        if (!initialized) {
+            properties = props;
+            initialized = true;
+            return;
+        }
         LOGGER.debug("Configuration updated for bean={} / pid={}", beanName, persistentId);
         synchronized (lock) {
             properties = props;

Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java Mon Sep  5 12:19:33 2016
@@ -50,6 +50,7 @@ public class CmProperties implements Man
     private final Object lock = new Object();
     private final Set<ServicePropertiesUpdater> services = new HashSet<ServicePropertiesUpdater>();
     private final Properties properties = new Properties();
+    private boolean initialized;
 
     public ExtendedBlueprintContainer getBlueprintContainer() {
         return blueprintContainer;
@@ -118,11 +119,6 @@ public class CmProperties implements Man
                 
         synchronized (lock) {
             managedObjectManager.register(this, props);
-            Configuration config = CmUtils.getConfiguration(configAdmin, persistentId);
-            if (config != null) {
-                properties.clear();
-                JavaUtils.copy(properties, config.getProperties());
-            }
         }
     }
 
@@ -135,10 +131,12 @@ public class CmProperties implements Man
     }
 
     public void updated(Dictionary props) {
-        if (serviceId != null) {
-            LOGGER.debug("Service properties updated for service={} / pid={}, {}", new Object[] {serviceId, persistentId, props});
-        } else {
-            LOGGER.debug("Service properties updated for pid={}, {}", new Object[] {persistentId, props});
+        if (initialized) {
+            if (serviceId != null) {
+                LOGGER.debug("Service properties updated for service={} / pid={}, {}", new Object[]{serviceId, persistentId, props});
+            } else {
+                LOGGER.debug("Service properties updated for pid={}, {}", new Object[]{persistentId, props});
+            }
         }
         
         synchronized (lock) {
@@ -146,7 +144,9 @@ public class CmProperties implements Man
             if (props != null) {
                 JavaUtils.copy(properties, props);
             }
-            if (update) {
+            if (!initialized) {
+                initialized = true;
+            } else if (update) {
                 for (ServicePropertiesUpdater service : services) {
                     service.updateProperties(props);
                 }
@@ -163,9 +163,7 @@ public class CmProperties implements Man
         
         synchronized (lock) {
             services.add(service);
-            if (properties != null) {
-                JavaUtils.copy(props, properties);
-            }
+            JavaUtils.copy(props, properties);
         }
     }
 

Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java Mon Sep  5 12:19:33 2016
@@ -46,6 +46,7 @@ public class CmPropertyPlaceholder exten
     private String updateStrategy;
     private ManagedObjectManager managedObjectManager;
     private Dictionary<String,Object> properties;
+    private boolean initialized;
 
     public ExtendedBlueprintContainer getBlueprintContainer() {
         return blueprintContainer;
@@ -89,10 +90,6 @@ public class CmPropertyPlaceholder exten
 
     public void init() throws Exception {
         LOGGER.debug("Initializing CmPropertyPlaceholder");
-        Configuration config = CmUtils.getConfiguration(configAdmin, persistentId);
-        if (config != null) {
-            properties = config.getProperties();
-        }
         Properties props = new Properties();
         props.put(Constants.SERVICE_PID, persistentId);
         Bundle bundle = blueprintContainer.getBundleContext().getBundle();
@@ -128,6 +125,11 @@ public class CmPropertyPlaceholder exten
     }
 
     public void updated(Dictionary props) {
+        if (!initialized) {
+            properties = props;
+            initialized = true;
+            return;
+        }
         if ("reload".equalsIgnoreCase(updateStrategy) && !equals(properties, props)) {
             LOGGER.debug("Configuration updated for pid={}", persistentId);
             // Run in a separate thread to avoid re-entrance

Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java Mon Sep  5 12:19:33 2016
@@ -19,11 +19,20 @@
 package org.apache.aries.blueprint.compendium.cm;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
 
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationPlugin;
 
 public class CmUtils  {
 
@@ -47,5 +56,179 @@ public class CmUtils  {
             return null;
         }
     }
-  
+
+    public static Dictionary<String, Object> getProperties(ServiceReference service, String persistentId) throws IOException {
+        BundleContext bc = service.getBundle().getBundleContext();
+        ServiceReference<ConfigurationAdmin> caRef = bc.getServiceReference(ConfigurationAdmin.class);
+        try {
+            ConfigurationAdmin ca = bc.getService(caRef);
+            Configuration config = getConfiguration(ca, persistentId);
+            if (config != null) {
+                Dictionary<String, Object> props = new CaseInsensitiveDictionary(config.getProperties());
+                BundleContext caBc = caRef.getBundle().getBundleContext();
+                callPlugins(caBc, props, service, persistentId, null);
+                return props;
+            } else {
+                return null;
+            }
+        } finally {
+            bc.ungetService(caRef);
+        }
+    }
+
+    private static void callPlugins(final BundleContext bundleContext,
+                                    final Dictionary<String, Object> props,
+                                    final ServiceReference sr,
+                                    final String configPid,
+                                    final String factoryPid) {
+        ServiceReference[] plugins = null;
+        try {
+            final String targetPid = (factoryPid == null) ? configPid : factoryPid;
+            String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
+            plugins = bundleContext.getServiceReferences(ConfigurationPlugin.class.getName(), filter);
+        } catch (InvalidSyntaxException ise) {
+            // no filter, no exception ...
+        }
+
+        // abort early if there are no plugins
+        if (plugins == null || plugins.length == 0) {
+            return;
+        }
+
+        // sort the plugins by their service.cmRanking
+        if (plugins.length > 1) {
+            Arrays.sort(plugins, CM_RANKING);
+        }
+
+        // call the plugins in order
+        for (ServiceReference pluginRef : plugins) {
+            ConfigurationPlugin plugin = (ConfigurationPlugin) bundleContext.getService(pluginRef);
+            if (plugin != null) {
+                try {
+                    plugin.modifyConfiguration(sr, props);
+                } catch (Throwable t) {
+                    // Ignore
+                } finally {
+                    // ensure ungetting the plugin
+                    bundleContext.ungetService(pluginRef);
+                }
+                setAutoProperties(props, configPid, factoryPid);
+            }
+        }
+    }
+
+    private static void setAutoProperties( Dictionary<String, Object> properties, String pid, String factoryPid )
+    {
+        replaceProperty(properties, Constants.SERVICE_PID, pid);
+        replaceProperty(properties, ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);
+        properties.remove(ConfigurationAdmin.SERVICE_BUNDLELOCATION);
+    }
+
+    private static void replaceProperty(Dictionary<String, Object> properties, String key, String value) {
+        if (value == null) {
+            properties.remove(key);
+        } else {
+            properties.put(key, value);
+        }
+    }
+
+    private static Comparator<ServiceReference> CM_RANKING = new Comparator<ServiceReference>() {
+        @Override
+        public int compare(ServiceReference sr1, ServiceReference sr2) {
+            final long rank1 = getLong(sr1, ConfigurationPlugin.CM_RANKING);
+            final long rank2 = getLong(sr2, ConfigurationPlugin.CM_RANKING);
+            if (rank1 == rank2) {
+                return 0;
+            }
+            return (rank1 < rank2) ? -1 : 1;
+        }
+
+        protected long getLong(ServiceReference sr, String property) {
+            Object rankObj = sr.getProperty(property);
+            if (rankObj instanceof Number) {
+                return ((Number) rankObj).longValue();
+            }
+            return 0;
+        }
+    };
+
+    private static class CaseInsensitiveDictionary extends Dictionary<String, Object> {
+        private final Hashtable<String, Object> internalMap = new Hashtable<String, Object>();
+        private final Hashtable<String, String> originalKeys = new Hashtable<String, String>();
+
+        public CaseInsensitiveDictionary(Dictionary<String, Object> props) {
+            if (props != null) {
+                Enumeration<String> keys = props.keys();
+                while (keys.hasMoreElements()) {
+                    // check the correct syntax of the key
+                    String key = checkKey(keys.nextElement());
+                    // check uniqueness of key
+                    String lowerCase = key.toLowerCase();
+                    if (internalMap.containsKey(lowerCase)) {
+                        throw new IllegalArgumentException("Key [" + key + "] already present in different case");
+                    }
+                    // check the value
+                    Object value = props.get(key);
+                    checkValue(value);
+                    // add the key/value pair
+                    internalMap.put(lowerCase, value);
+                    originalKeys.put(lowerCase, key);
+                }
+            }
+        }
+
+        public Enumeration<Object> elements() {
+            return Collections.enumeration(internalMap.values());
+        }
+
+        public Object get(Object keyObj) {
+            String lowerCase = checkKey(keyObj == null ? null : keyObj.toString()).toLowerCase();
+            return internalMap.get(lowerCase);
+        }
+
+        public boolean isEmpty() {
+            return internalMap.isEmpty();
+        }
+
+        public Enumeration<String> keys() {
+            return Collections.enumeration(originalKeys.values());
+        }
+
+        public Object put(String key, Object value) {
+            String lowerCase = checkKey(key).toLowerCase();
+            checkValue(value);
+            originalKeys.put(lowerCase, key);
+            return internalMap.put(lowerCase, value);
+        }
+
+        public Object remove(Object keyObj) {
+            String lowerCase = checkKey(keyObj == null ? null : keyObj.toString()).toLowerCase();
+            originalKeys.remove(lowerCase);
+            return internalMap.remove(lowerCase);
+        }
+
+        public int size() {
+            return internalMap.size();
+        }
+
+        static String checkKey(String key) {
+            if (key == null || key.length() == 0) {
+                throw new IllegalArgumentException("Key must not be null nor an empty string");
+            }
+            return key;
+        }
+
+        static Object checkValue(Object value) {
+            if (value == null) {
+                throw new IllegalArgumentException("Value must not be null");
+            }
+            return value;
+        }
+
+        public String toString() {
+            return internalMap.toString();
+        }
+
+    }
+
 }

Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java Mon Sep  5 12:19:33 2016
@@ -25,6 +25,8 @@ import java.util.Properties;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.aries.util.AriesFrameworkUtil;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
@@ -51,6 +53,13 @@ public class ManagedObjectManager {
             map.put(key, reg);
         }
         reg.add(cm);
+
+        try {
+            Dictionary<String, Object> config = CmUtils.getProperties(reg.getRegistration().getReference(), key);
+            cm.updated(config);
+        } catch (Throwable t) {
+            // Ignore
+        }
     }
 
     public synchronized void unregister(ManagedObject cm) {

Modified: aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/TestConfigAdmin.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/TestConfigAdmin.java?rev=1759245&r1=1759244&r2=1759245&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/TestConfigAdmin.java (original)
+++ aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/TestConfigAdmin.java Mon Sep  5 12:19:33 2016
@@ -117,6 +117,13 @@ public class TestConfigAdmin extends Abs
         assertEquals("Multiple services were registered for the same pid.", 1, refs.length);
     }
 
+    @Test
+    public void testPlaceholder() throws Exception {
+        Configuration cf = ca.getConfiguration("blueprint-sample-placeholder", null);
+        cf.update(getConfig3());
+        startTestBundle();
+    }
+
     private Hashtable<String, String> getConfig1() {
         Hashtable<String,String> props = new Hashtable<String,String>();
         props.put("a", "5");
@@ -132,6 +139,13 @@ public class TestConfigAdmin extends Abs
         return props;
     }
 
+    private Hashtable<String, String> getConfig3() {
+        Hashtable<String, String> props;
+        props = new Hashtable<String,String>();
+        props.put("key.b", "10");
+        return props;
+    }
+
     private <T>T getComponent(String componentId) {
         BlueprintContainer blueprintContainer = Helper.getBlueprintContainerForBundle(context(), "org.apache.aries.blueprint.sample");
         assertNotNull(blueprintContainer);