felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fmesc...@apache.org
Subject svn commit: r805668 - /felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
Date Wed, 19 Aug 2009 05:54:40 GMT
Author: fmeschbe
Date: Wed Aug 19 05:54:40 2009
New Revision: 805668

URL: http://svn.apache.org/viewvc?rev=805668&view=rev
Log:
FELIX-1146 refactor update tasks to immediately gather configurations
   and properties for asynchronous delivery. This not completely eliminates
   potential dual delivery but limits the probability dramatically
   (see issue for further discussion)
FELIX-1488 adapt to new configuration/factory binding API

Modified:
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java?rev=805668&r1=805667&r2=805668&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
(original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
Wed Aug 19 05:54:40 2009
@@ -593,10 +593,9 @@
             for ( int i = 0; i < configs.length; i++ )
             {
                 final ConfigurationImpl cfg = configs[i];
-                if ( location.equals( cfg.getBundleLocation() ) )
+                if ( location.equals( cfg.getDynamicBundleLocation() ) )
                 {
-                    // reset dynamic binding
-                    cfg.setBundleLocation( null, false );
+                    cfg.setDynamicBundleLocation( null );
                 }
             }
 
@@ -606,10 +605,9 @@
             for ( int i = 0; i < factories.length; i++ )
             {
                 final Factory factory = factories[i];
-                if ( location.equals( factory.getBundleLocation() ) )
+                if ( location.equals( factory.getDynamicBundleLocation() ) )
                 {
-                    // reset dynamic binding
-                    factory.setBundleLocation( null, false );
+                    factory.setDynamicBundleLocation( null );
                 }
             }
         }
@@ -761,9 +759,12 @@
 
     /**
      * Calls the registered configuration plugins on the given configuration
-     * object unless the configuration has just been created and not been
-     * updated yet.
+     * properties from the given configuration object unless the configuration
+     * has just been created and not been updated yet.
      *
+     * @param props The configuraiton properties run through the registered
+     *          ConfigurationPlugin services. This may be <code>null</code>
+     *          in which case this method just immediately returns.
      * @param targetPid The identification of the configuration update used to
      *          select the plugins according to their cm.target service
      *          property
@@ -771,19 +772,13 @@
      *          is to be updated with configuration
      * @param cfg The configuration object whose properties have to be passed
      *          through the plugins
-     * @return The properties from the configuration object passed through the
-     *         plugins or <code>null</code> if the configuration object has
-     *         been newly created and no properties exist yet.
      */
-    private Dictionary callPlugins( final String targetPid, final ServiceReference sr, final
ConfigurationImpl cfg )
+    private void callPlugins( final Dictionary props, final String targetPid, final ServiceReference
sr,
+        final ConfigurationImpl cfg )
     {
-        // return a deep copy, since the plugins may tamper with the array
-        // and collection elements, which should not modify the internal data
-        Dictionary props = cfg.getProperties( true );
-
         // guard against NPE for new configuration never updated
         if (props == null) {
-            return null;
+            return;
         }
 
         ServiceReference[] plugins = null;
@@ -800,7 +795,7 @@
         // abort early if there are no plugins
         if ( plugins == null || plugins.length == 0 )
         {
-            return props;
+            return;
         }
 
         // sort the plugins by their service.cmRanking
@@ -821,7 +816,8 @@
             }
             catch ( Throwable t )
             {
-                log( LogService.LOG_ERROR, "Unexpected problem calling" + " configuration
plugin", t );
+                log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin
" + toString( pluginRef ),
+                    t );
             }
             finally
             {
@@ -830,8 +826,6 @@
             }
             cfg.setAutoProperties( props, false );
         }
-
-        return props;
     }
 
 
@@ -960,51 +954,70 @@
         return null;
     }
 
+
+    static String toString( ServiceReference ref )
+    {
+        String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
+        String oc = "[";
+        for ( int i = 0; i < ocs.length; i++ )
+        {
+            oc += ocs[i];
+            if ( i < ocs.length - 1 )
+                oc += ", ";
+        }
+
+        oc += ", id=" + ref.getProperty( Constants.SERVICE_ID );
+        oc += ", bundle=" + ref.getBundle().getBundleId();
+        oc += "]";
+        return oc;
+    }
+
     // ---------- inner classes ------------------------------------------------
 
     private class ManagedServiceUpdate implements Runnable
     {
-        private String pid;
+        private final String pid;
+
+        private final ServiceReference sr;
 
-        private ServiceReference sr;
+        private final ManagedService service;
 
-        private ManagedService service;
+        private final ConfigurationImpl config;
 
+        private final Dictionary rawProperties;
 
         ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
         {
             this.pid = pid;
             this.sr = sr;
             this.service = service;
-        }
 
-
-        public void run()
-        {
             // get or load configuration for the pid
-            ConfigurationImpl cfg;
+            ConfigurationImpl config = null;
+            Dictionary rawProperties = null;
             try
             {
-                cfg = getExistingConfiguration( pid );
+                config = getExistingConfiguration( pid );
+                if (config != null) {
+                    rawProperties = config.getProperties( true );
+                }
             }
             catch ( IOException ioe )
             {
                 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe
);
-                return;
             }
 
-            // this will be set below to be given to the service
-            Dictionary dictionary;
+            this.config = config;
+            this.rawProperties = rawProperties;
+        }
+
 
+        public void run()
+        {
             // check configuration and call plugins if existing
-            if ( cfg != null )
+            Dictionary properties = rawProperties;
+            if ( config != null )
             {
-                if ( cfg.isDelivered() )
-                {
-                    log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been
delivered", null );
-                    return;
-                }
-
                 Bundle serviceBundle = sr.getBundle();
                 if ( serviceBundle == null )
                 {
@@ -1018,52 +1031,42 @@
                 // 104.4.1 No update call back for PID already bound to another
                 // bundle location
                 // 104.4.1 assign configuration to bundle if unassigned
-                String bundleLocation = serviceBundle.getLocation();
-                if ( cfg.getBundleLocation() == null )
-                {
-                    // dynamically bind to the location of the service if unbound
-                    cfg.setBundleLocation( bundleLocation, false );
-                }
-                else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
+                if ( !config.tryBindLocation( serviceBundle.getLocation() ) )
                 {
-                    log( LogService.LOG_ERROR, "Cannot use configuration for " + pid + "
requested by bundle "
-                        + serviceBundle.getLocation() + " but belongs to " + cfg.getBundleLocation(),
null );
+                    log( LogService.LOG_ERROR, "Cannot use configuration " + pid + " for
"
+                        + ConfigurationManager.toString( sr ) + ": Configuration bound to
bundle "
+                        + config.getBundleLocation(), null );
                     return;
                 }
 
                 // 104.3 Report an error in the log if more than one service
                 // with the same PID asks for the configuration
-                if ( cfg.getServiceReference() != null && !sr.equals( cfg.getServiceReference()
) )
+                if ( config.getServiceReference() == null )
                 {
-                    log( LogService.LOG_ERROR, "Configuration for " + pid + " has already
been used for service "
-                        + cfg.getServiceReference() + " and will now also be given to " +
sr, null );
+                    // assign the configuration to the service
+                    config.setServiceReference( sr );
                 }
-                else
+                else if ( !sr.equals( config.getServiceReference() ) )
                 {
-                    // assign the configuration to the service
-                    cfg.setServiceReference( sr );
+                    log( LogService.LOG_ERROR, "Configuration for " + pid + " has already
been used for service "
+                        + ConfigurationManager.toString( config.getServiceReference() )
+                        + " and will now also be given to " + ConfigurationManager.toString(
sr ), null );
                 }
 
                 // prepare the configuration for the service (call plugins)
-                dictionary = callPlugins( pid, sr, cfg );
+                callPlugins( properties, pid, sr, config );
             }
             else
             {
                 // 104.5.3 ManagedService.updated must be called with null
                 // if no configuration is available
-                dictionary = null;
+                properties = null;
             }
 
             // update the service with the configuration
             try
             {
-                service.updated( dictionary );
-
-                // if there is nothing to set, don't
-                if ( cfg != null )
-                {
-                    cfg.setDelivered( true );
-	            }
+                service.updated( properties );
             }
             catch ( ConfigurationException ce )
             {
@@ -1092,34 +1095,89 @@
 
     private class ManagedServiceFactoryUpdate implements Runnable
     {
-        private String factoryPid;
+        private final String factoryPid;
 
-        private ServiceReference sr;
+        private final ServiceReference sr;
 
-        private ManagedServiceFactory service;
+        private final ManagedServiceFactory service;
 
+        private final Factory factory;
+
+        private final Map configs;
 
         ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory
service )
         {
             this.factoryPid = factoryPid;
             this.sr = sr;
             this.service = service;
-        }
-
 
-        public void run()
-        {
-            Factory factory;
+            Factory factory = null;
+            Map configs = null;
             try
             {
                 factory = getFactory( factoryPid );
+                if (factory != null) {
+                    configs = new HashMap();
+                    for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
+                    {
+                        final String pid = ( String ) pi.next();
+                        ConfigurationImpl cfg;
+                        try
+                        {
+                            cfg = getExistingConfiguration( pid );
+                        }
+                        catch ( IOException ioe )
+                        {
+                            log( LogService.LOG_ERROR, "Error loading configuration for "
+ pid, ioe );
+                            continue;
+                        }
+
+                        // sanity check on the configuration
+                        if ( cfg == null )
+                        {
+                            log( LogService.LOG_ERROR, "Configuration " + pid + " referred
to by factory " + factoryPid
+                                + " does not exist", null );
+                            factory.removePID( pid );
+                            factory.storeSilently();
+                            continue;
+                        }
+                        else if ( cfg.isNew() )
+                        {
+                            // Configuration has just been created but not yet updated
+                            // we currently just ignore it and have the update mechanism
+                            // provide the configuration to the ManagedServiceFactory
+                            // As of FELIX-612 (not storing new factory configurations)
+                            // this should not happen. We keep this for added stability
+                            // but raise the logging level to error.
+                            log( LogService.LOG_ERROR, "Ignoring new configuration pid="
+ pid, null );
+                            continue;
+                        }
+                        else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
+                        {
+                            log( LogService.LOG_ERROR, "Configuration " + pid + " referred
to by factory " + factoryPid
+                                + " seems to belong to factory " + cfg.getFactoryPid(), null
);
+                            factory.removePID( pid );
+                            factory.storeSilently();
+                            continue;
+                        }
+
+                        // get the configuration properties for later
+                        configs.put(cfg, cfg.getProperties( true ));
+                    }
+                }
             }
             catch ( IOException ioe )
             {
                 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID "
+ factoryPid, ioe );
-                return;
             }
 
+            this.factory = factory;
+            this.configs = configs;
+        }
+
+
+        public void run()
+        {
             Bundle serviceBundle = sr.getBundle();
             if ( serviceBundle == null )
             {
@@ -1128,102 +1186,62 @@
                 return;
             }
 
-            String bundleLocation = serviceBundle.getLocation();
-            if ( factory.getBundleLocation() == null )
-            {
-                // bind to the location of the service if unbound
-                factory.setBundleLocation( bundleLocation, false );
-            }
-            else if ( !bundleLocation.equals( factory.getBundleLocation() ) )
+            final String serviceBundleLocation = serviceBundle.getLocation();
+            if ( !factory.tryBindLocation( serviceBundleLocation ) )
             {
                 // factory PID is bound to another bundle
-                log( LogService.LOG_ERROR, "Cannot use Factory configuration for " + factoryPid
-                    + " requested by bundle " + serviceBundle.getLocation() + " but belongs
to "
+                log( LogService.LOG_ERROR, "Cannot use factory configuration " + factoryPid
+ " for "
+                    + ConfigurationManager.toString( sr ) + ": Configuration bound to bundle
"
                     + factory.getBundleLocation(), null );
+
                 return;
             }
 
-            Set pids = factory.getPIDs();
-
-            for ( Iterator pi = pids.iterator(); pi.hasNext(); )
+            for ( Iterator ci=configs.entrySet().iterator(); ci.hasNext(); )
             {
-                String pid = ( String ) pi.next();
-                ConfigurationImpl cfg;
-                try
-                {
-                    cfg = getExistingConfiguration( pid );
-                }
-                catch ( IOException ioe )
-                {
-                    log( LogService.LOG_ERROR, "Error loading configuration for " + pid,
ioe );
-                    continue;
-                }
+                final Map.Entry entry = (Map.Entry) ci.next();
+                final ConfigurationImpl cfg = (ConfigurationImpl) entry.getKey();
+                final Dictionary properties = (Dictionary) entry.getValue();
 
-                // sanity check on the configuration
-                if ( cfg == null )
-                {
-                    log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by
factory " + factoryPid
-                        + " does not exist", null );
-                    factory.removePID( pid );
-                    factory.storeSilently();
-                    continue;
-                }
-                else if ( cfg.isNew() )
-                {
-                    // Configuration has just been created but not yet updated
-                    // we currently just ignore it and have the update mechanism
-                    // provide the configuration to the ManagedServiceFactory
-                    // As of FELIX-612 (not storing new factory configurations)
-                    // this should not happen. We keep this for added stability
-                    // but raise the logging level to error.
-                    log( LogService.LOG_ERROR, "Ignoring new configuration pid=" + pid, null
);
-                    continue;
-                }
-                else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
+                // check bundle location of configuration
+                if ( !cfg.tryBindLocation( serviceBundleLocation ) )
                 {
-                    log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by
factory " + factoryPid
-                        + " seems to belong to factory " + cfg.getFactoryPid(), null );
-                    factory.removePID( pid );
-                    factory.storeSilently();
-                    continue;
-                }
+                    // configuration is bound to another bundle
+                    log( LogService.LOG_ERROR, "Cannot use configuration " + cfg.getPid()
+ " (factory " + factoryPid
+                        + ") for " + ConfigurationManager.toString( sr ) + ": Configuration
bound to bundle "
+                        + cfg.getBundleLocation(), null );
 
-                // do not re-updated unmodified configuration
-                if ( cfg.isDelivered() )
-                {
-                    log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been
updated", null );
                     continue;
                 }
 
-                // check bundle location of configuration
-                if ( cfg.getBundleLocation() == null )
+                // 104.3 Report an error in the log if more than one service
+                // with the same PID asks for the configuration
+                if ( cfg.getServiceReference() == null )
                 {
-                    // dynamically bind to the location of the service if unbound
-                    cfg.setBundleLocation( bundleLocation, false );
+                    // assign the configuration to the service
+                    cfg.setServiceReference( sr );
                 }
-                else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
+                else if ( !sr.equals( cfg.getServiceReference() ) )
                 {
-                    // configuration is bound to another bundle
-                    log( LogService.LOG_ERROR, "Configuration " + pid + " (factory " + factoryPid
-                        + ") belongs to bundle " + cfg.getBundleLocation() + " but was requested
for bundle "
-                        + bundleLocation, null );
-                    continue;
+                    log( LogService.LOG_ERROR, "Configuration for " + cfg.getPid() + " (factory
" + factoryPid
+                        + ") has already been used for service "
+                        + ConfigurationManager.toString( cfg.getServiceReference() )
+                        + " and will now also be given to " + ConfigurationManager.toString(
sr ), null );
                 }
 
                 // prepare the configuration for the service (call plugins)
                 // call the plugins with cm.target set to the service's factory PID
                 // (clarification in Section 104.9.1 of Compendium 4.2)
-                Dictionary dictionary = callPlugins( factoryPid, sr, cfg );
+                callPlugins( properties, factoryPid, sr, cfg );
 
                 // update the service with the configuration
                 try
                 {
                     // only, if there is non-null configuration data
-                    if ( dictionary != null )
+                    if ( properties  != null )
                     {
-                        log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" +
pid, null );
-                        service.updated( pid, dictionary );
-                        cfg.setDelivered( true );
+                        log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" +
cfg.getPid(), null );
+                        service.updated( cfg.getPid(), properties );
                     }
                 }
                 catch ( ConfigurationException ce )
@@ -1257,12 +1275,15 @@
     private class UpdateConfiguration implements Runnable
     {
 
-        private ConfigurationImpl config;
+        private final ConfigurationImpl config;
+
+        private final Dictionary properties;
 
 
-        UpdateConfiguration( ConfigurationImpl config )
+        UpdateConfiguration( final ConfigurationImpl config )
         {
             this.config = config;
+            this.properties = config.getProperties( true );
         }
 
 
@@ -1270,69 +1291,65 @@
         {
             try
             {
-                if ( config.isDelivered() )
-                {
-                    log( LogService.LOG_DEBUG, "Configuration " + config.getPid() + " has
already been updated", null );
-                    return;
-                }
-
                 if ( config.getFactoryPid() == null )
                 {
                     final ServiceReference[] srList = bundleContext.getServiceReferences(
ManagedService.class
                         .getName(), "(" + Constants.SERVICE_PID + "=" + config.getPid() +
")" );
-                    if ( srList != null && srList.length > 0 )
+                    if ( srList != null )
                     {
-                        final ServiceReference sr = srList[0];
-                        final ManagedService srv = ( ManagedService ) bundleContext.getService(
sr );
+                        // find the primary configuration owner
+                        final ServiceReference ownerRef = getOwner( config, srList );
+                        final String bundleLocation = ownerRef.getBundle().getLocation();
 
-                        // 104.3 Report an error in the log if more than one service
-                        // with the same PID asks for the configuration
-                        if ( srList.length > 1 )
+                        // if the configuration is unbound, bind to owner
+                        if ( config.getBundleLocation() == null )
                         {
-                            for ( int i = 1; i < srList.length; i++ )
-                            {
-                                log( LogService.LOG_ERROR, "Configuration for " + config.getPid()
-                                    + " is used for service " + sr
-                                    + "following services will not receive configuration:
" + srList[i], null );
-                            }
+                            config.setDynamicBundleLocation( bundleLocation );
                         }
+                        final String configBundleLocation = config.getBundleLocation();
 
-                        try
+                        // provide configuration to all services from the
+                        // correct bundle
+                        for ( int i = 0; i < srList.length; i++ )
                         {
-                            // bind the configuration, fail if bound to another
-                            // bundle !!
-                            // check bundle location of configuration
-                            String bundleLocation = sr.getBundle().getLocation();
-                            if ( config.getBundleLocation() == null )
+
+                            final ServiceReference userRef = srList[i];
+                            final String userRefLocation = userRef.getBundle().getLocation();
+
+                            // only consider the entry if in the same bundle
+                            if ( !userRefLocation.equals( configBundleLocation ) )
                             {
-                                // dynamically bind to the location of the service if unbound
-                                config.setBundleLocation( bundleLocation, false );
+                                log( LogService.LOG_ERROR, "Cannot use configuration " +
config.getPid() + " for "
+                                    + ConfigurationManager.toString( userRef ) + ": Configuration
bound to bundle "
+                                    + configBundleLocation, null );
+
+                                continue;
                             }
-                            else if ( !bundleLocation.equals( config.getBundleLocation()
) )
+
+                            // 104.3 Report an error in the log if more than one
+                            // service with the same PID asks for the
+                            // configuration
+                            if ( userRef != ownerRef )
                             {
-                                // configuration is bound to another bundle
-                                log( LogService.LOG_ERROR, "Configuration " + config.getPid()
+ " belongs to bundle "
-                                    + config.getBundleLocation() + " but was requested for
bundle " + bundleLocation,
-                                    null );
-                                return;
+                                log( LogService.LOG_ERROR, "Configuration for " + config.getPid()
+                                    + " has already been used for service " + ConfigurationManager.toString(
ownerRef )
+                                    + " and will now also be given to " + ConfigurationManager.toString(
userRef ), null );
                             }
 
-                            // record the delivery of the configuration
-                            if ( config.getServiceReference() == null )
+                            try
                             {
-                                config.setServiceReference( sr );
+                                final ManagedService srv = ( ManagedService ) bundleContext.getService(
userRef );
+                                if ( srv != null )
+                                {
+                                    Dictionary props = new CaseInsensitiveDictionary( properties
);
+                                    callPlugins( props, config.getPid(), userRef, config
);
+                                    srv.updated( props );
+                                }
+                            }
+                            finally
+                            {
+                                bundleContext.ungetService( userRef );
                             }
-
-                            // prepare the configuration for the service (call plugins)
-                            Dictionary dictionary = callPlugins( config.getPid(), sr, config
);
-
-                            // update the ManagedService with the properties
-                            srv.updated( dictionary );
-                            config.setDelivered( true );
-                        }
-                        finally
-                        {
-                            bundleContext.ungetService( sr );
                         }
                     }
                 }
@@ -1342,44 +1359,59 @@
                         .getName(), "(" + Constants.SERVICE_PID + "=" + config.getFactoryPid()
+ ")" );
                     if ( srList != null && srList.length > 0 )
                     {
-                        final ServiceReference sr = srList[0];
-                        final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService(
sr );
-                        try
+                        // find the primary configuration owner
+                        final ServiceReference ownerRef = getOwner( config, srList );
+                        final String bundleLocation = ownerRef.getBundle().getLocation();
+
+                        // if the configuration is unbound, bind to owner
+                        if ( config.getBundleLocation() == null )
                         {
-                            // bind the configuration, fail if bound to another
-                            // bundle !!
-                            // check bundle location of configuration
-                            String bundleLocation = sr.getBundle().getLocation();
-                            if ( config.getBundleLocation() == null )
+                            config.setDynamicBundleLocation( bundleLocation );
+                        }
+
+                        // provide configuration to all services from the
+                        // correct bundle
+                        for ( int i = 0; i < srList.length; i++ )
+                        {
+                            final ServiceReference ref = srList[i];
+                            final String refLocation = ref.getBundle().getLocation();
+
+                            // only consider the entry if in the same bundle
+                            if ( !refLocation.equals( config.getBundleLocation() ) )
                             {
-                                // dynamically bind to the location of the service if unbound
-                                config.setBundleLocation( bundleLocation, false );
+                                log( LogService.LOG_ERROR, "Cannot use configuration " +
config.getPid() + " (factory "
+                                    + config.getFactoryPid() + ") for " + ConfigurationManager.toString(
ref )
+                                    + ": Configuration bound to bundle " + config.getBundleLocation(),
null );
+
+                                continue;
                             }
-                            else if ( !bundleLocation.equals( config.getBundleLocation()
) )
+
+                            // 104.3 Report an error in the log if more than one
+                            // service with the same PID asks for the
+                            // configuration
+                            if ( ref != ownerRef )
                             {
-                                // configuration is bound to another bundle
-                                log( LogService.LOG_ERROR, "Configuration " + config.getPid()
+ " (factory "
-                                    + config.getFactoryPid() + ") belongs to bundle " + config.getBundleLocation()
-                                    + " but was requested for bundle " + bundleLocation,
null );
-                                return;
+                                log( LogService.LOG_ERROR, "Configuration for " + config.getPid()
+ " (factory "
+                                    + config.getFactoryPid() + ") has already been used for
service "
+                                    + ConfigurationManager.toString( ownerRef ) + " and will
now also be given to "
+                                    + ConfigurationManager.toString( ref ), null );
                             }
 
-                            // prepare the configuration for the service (call plugins)
-                            // call the plugins with cm.target set to the service's factory
PID
-                            // (clarification in Section 104.9.1 of Compendium 4.2)
-                            Dictionary dictionary = callPlugins( config.getFactoryPid(),
sr, config );
-
-                            // update the ManagedServiceFactory with the properties
-                            // only, if there is non-null configuration data
-                            if ( dictionary != null )
+                            try
                             {
-                                srv.updated( config.getPid(), dictionary );
-                                config.setDelivered( true );
+                                final ManagedServiceFactory srv = ( ManagedServiceFactory
) bundleContext
+                                    .getService( ref );
+                                if ( srv != null && properties != null )
+                                {
+                                    Dictionary props = new CaseInsensitiveDictionary( properties
);
+                                    callPlugins( props, config.getFactoryPid(), ref, config
);
+                                    srv.updated( config.getPid(), props );
+                                }
+                            }
+                            finally
+                            {
+                                bundleContext.ungetService( ref );
                             }
-                        }
-                        finally
-                        {
-                            bundleContext.ungetService( sr );
                         }
                     }
                 }
@@ -1409,6 +1441,29 @@
             }
         }
 
+
+        private ServiceReference getOwner( ConfigurationImpl config, ServiceReference[] srList
)
+        {
+            // find the current owner among the references (if any)
+            if ( config.getServiceReference() != null )
+            {
+                for ( int i = 0; i < srList.length; i++ )
+                {
+                    if ( srList[i].equals( config.getServiceReference() ) )
+                    {
+                        return srList[i];
+                    }
+                }
+            }
+
+            // configuration has never been supplied or the binding is stale
+            // just use the first entry in the list as the new owner
+            final ServiceReference ownerRef = srList[0];
+            config.setServiceReference( ownerRef );
+            return ownerRef;
+        }
+
+
         public String toString()
         {
             return "Update: pid=" + config.getPid();
@@ -1435,28 +1490,30 @@
         {
             try
             {
-                if ( config.isDelivered() )
-                {
-                    log( LogService.LOG_DEBUG, "Deletion of configuration " + pid + " has
already been delivered", null );
-                    return;
-                }
+                final String configLocation = config.getBundleLocation();
 
                 if ( factoryPid == null )
                 {
                     ServiceReference[] srList = bundleContext.getServiceReferences( ManagedService.class.getName(),
"("
                         + Constants.SERVICE_PID + "=" + pid + ")" );
-                    if ( srList != null && srList.length > 0 )
+                    if ( srList != null )
                     {
-                        final ServiceReference sr = srList[0];
-                        final ManagedService srv = ( ManagedService ) bundleContext.getService(
sr );
-                        try
-                        {
-                            srv.updated( null );
-                            config.setDelivered( true );
-                        }
-                        finally
+                        for ( int i = 0; i < srList.length; i++ )
                         {
-                            bundleContext.ungetService( sr );
+                            final ServiceReference sr = srList[i];
+                            if ( sr.getBundle().getLocation().equals( configLocation ) )
+                            {
+                                // only if the service is from the bound bundle
+                                final ManagedService srv = ( ManagedService ) bundleContext.getService(
sr );
+                                try
+                                {
+                                    srv.updated( null );
+                                }
+                                finally
+                                {
+                                    bundleContext.ungetService( sr );
+                                }
+                            }
                         }
                     }
                 }
@@ -1469,18 +1526,25 @@
 
                     ServiceReference[] srList = bundleContext.getServiceReferences( ManagedServiceFactory.class
                         .getName(), "(" + Constants.SERVICE_PID + "=" + factoryPid + ")"
);
-                    if ( srList != null && srList.length > 0 )
+                    if ( srList != null)
                     {
-                        final ServiceReference sr = srList[0];
-                        final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService(
sr );
-                        try
-                        {
-                            srv.deleted( pid );
-                            config.setDelivered( true );
-                        }
-                        finally
+                        for ( int i = 0; i < srList.length; i++ )
                         {
-                            bundleContext.ungetService( sr );
+                            final ServiceReference sr = srList[i];
+                            if ( sr.getBundle().getLocation().equals( configLocation ) )
+                            {
+                                // only if the service is from the bound bundle
+                                final ManagedServiceFactory srv = ( ManagedServiceFactory
) bundleContext
+                                    .getService( sr );
+                                try
+                                {
+                                    srv.deleted( pid );
+                                }
+                                finally
+                                {
+                                    bundleContext.ungetService( sr );
+                                }
+                            }
                         }
                     }
                 }
@@ -1553,7 +1617,8 @@
                 }
                 catch ( Throwable t )
                 {
-                    log( LogService.LOG_ERROR, "Unexpected problem delivery configuration
event to " + srs[i], t );
+                    log( LogService.LOG_ERROR, "Unexpected problem delivery configuration
event to "
+                        + ConfigurationManager.toString( srs[i] ), t );
                 }
             }
         }
@@ -1564,18 +1629,38 @@
         }
     }
 
-    private static abstract class AbstractManagedServiceTracker extends ServiceTracker
+    private static class ManagedServiceTracker extends ServiceTracker
     {
-        protected final ConfigurationManager cm;
 
-        AbstractManagedServiceTracker( ConfigurationManager cm, String className )
+        private final ConfigurationManager cm;
+
+
+        ManagedServiceTracker( ConfigurationManager cm )
         {
-            super( cm.bundleContext, className, null );
+            super( cm.bundleContext, ManagedService.class.getName(), null );
             this.cm = cm;
             open();
         }
 
 
+        public Object addingService( ServiceReference reference )
+        {
+            Object serviceObject = super.addingService( reference );
+
+            // configure the managed service
+            if ( serviceObject instanceof ManagedService )
+            {
+                cm.configure(reference, ( ManagedService ) serviceObject);
+            }
+            else
+            {
+                cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedService",
null );
+            }
+
+            return serviceObject;
+        }
+
+
         public void removedService( ServiceReference reference, Object service )
         {
             // check whether we can take back the configuration object
@@ -1588,7 +1673,6 @@
                     if ( cfg != null && reference.equals( cfg.getServiceReference()
) )
                     {
                         cfg.setServiceReference( null );
-                        cfg.setDelivered( false );
                     }
                 }
             }
@@ -1597,38 +1681,16 @@
         }
     }
 
-    private static class ManagedServiceTracker extends AbstractManagedServiceTracker
+    private static class ManagedServiceFactoryTracker extends ServiceTracker
     {
-
-        ManagedServiceTracker(ConfigurationManager cm)
-        {
-            super( cm, ManagedService.class.getName() );
-        }
+        private final ConfigurationManager cm;
 
 
-        public Object addingService( ServiceReference reference )
+        ManagedServiceFactoryTracker( ConfigurationManager cm )
         {
-            Object serviceObject = super.addingService( reference );
-
-            // configure the managed service
-            if ( serviceObject instanceof ManagedService )
-            {
-                cm.configure(reference, ( ManagedService ) serviceObject);
-            }
-            else
-            {
-                cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedService",
null );
-            }
-
-            return serviceObject;
-        }
-    }
-
-    private static class ManagedServiceFactoryTracker extends AbstractManagedServiceTracker
-    {
-        ManagedServiceFactoryTracker(ConfigurationManager cm)
-        {
-            super( cm, ManagedServiceFactory.class.getName() );
+            super( cm.bundleContext, ManagedServiceFactory.class.getName(), null );
+            this.cm = cm;
+            open();
         }
 
 
@@ -1665,9 +1727,9 @@
                         {
                             String pid = ( String ) pi.next();
                             ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
-                            if ( cfg != null )
+                            if ( cfg != null && reference.equals( cfg.getServiceReference()
) )
                             {
-                                cfg.setDelivered( false );
+                                cfg.setServiceReference( null );
                             }
                         }
                     }



Mime
View raw message