Hi Pierre,

Sorry for the late reply ...

Pierre De Rop schrieb:
> I am experimenting the following: I need to use ConfigAdmin (trunk) for
> configuring my components. I also uses SCR (trunk).
> Because we have our own specific configuration database, I first
> populate CM during startup like this:
> 
> 1) pre-load all configurations from our own database
> 
> 2) and for each PID loaded from our own database, when then populate CM
> like this:
> 
>       populateCM(String PID, Dictionary c) {
>          Configuration config = _cm.getConfiguration(PID, null);
>          if (config.getBundleLocation() != null)
>          {
>            config.setBundleLocation(null);
>          }
>          config.update(c);
>       }
> 
> 3) Now, because we have our own persistence manager, I don't want to let
> CM store all configuration in the default CM PersistenceManager.
> So, I have noticed that CM has a nice feature -> we can provide our own
> PersistenceManager.

That's what I would have proposed reading #1 and #2 above ;-)

> 
> 4) So, before SCR is started, I provide in the OSGi Registry my own
> PersistentManager: For now: this persistent manager is simple and just
> stores in
> a map all CM configuration, like this:
> 
> -----------------------------------------------------------------------------------------
> 
> public class MapPersistenceManager implements PersistenceManager
> {
>  private ConcurrentHashMap<String, Dictionary> _cmstore = new
> ConcurrentHashMap<String, Dictionary>();
> 
>  public void delete(String pid) throws IOException
>  {
>    _cmstore.remove(pid);
>  }
> 
>  public boolean exists(String pid)
>  {
>    return _cmstore.containsKey(pid);
>  }
> 
>  public Enumeration getDictionaries() throws IOException
>  {
>    return Collections.enumeration(_cmstore.values());
>  }
> 
>  public Dictionary load(String pid) throws IOException
>  {
>    Dictionary d = _cmstore.get(pid);
>    if (d == null) {
>      d = new Hashtable();
>    }
>    return d;
>  }
> 
>  public void store(String pid, Dictionary dic) throws IOException
>  {
>    _cmstore.put(pid, dic);
>  }
> }
> -----------------------------------------------------------------------------------------
> 
> 
> Notice that initially, I used a Map and I synchronized all my methods,
> but I then got the following exception:
> 
> java.util.ConcurrentModificationException
>        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
>        at java.util.HashMap$ValueIterator.next(HashMap.java:822)
>        at java.util.Collections$1.nextElement(Collections.java:3389)
>        at
> org.apache.felix.cm.impl.ConfigurationManager.listConfigurations(ConfigurationManager.java:518)
> 
>        at
> org.apache.felix.cm.impl.ConfigurationAdminImpl.listConfigurations(ConfigurationAdminImpl.java:124)
> 
>        at
> org.apache.felix.scr.impl.config.ConfigurationComponentRegistry.findConfigurations(ConfigurationComponentRegistry.java:248)
> 
>        at
> org.apache.felix.scr.impl.config.ConfigurationComponentRegistry.findFactoryConfigurations(ConfigurationComponentRegistry.java:240)
> 
>        at
> org.apache.felix.scr.impl.config.ConfigurationComponentRegistry.createComponentHolder(ConfigurationComponentRegistry.java:107)
> 
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:243)
> 
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:146)
> 
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:110)
> 
>        at
> org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:233)
>        at
> org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:169)
>        at
> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:800)
> 
>        at
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:728)
> 
>        at
> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:610)
> 
>        at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:3576)
>        at org.apache.felix.framework.Felix.startBundle(Felix.java:1650)
>        at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:915)
>        at
> com.alcatel.as.service.bundleinstaller.impl.BundleInstallerImpl$DeployedBundle.start(BundleInstallerImpl.java:1133)
> 
>        at
> com.alcatel.as.service.bundleinstaller.impl.BundleInstallerImpl.startBundles(BundleInstallerImpl.java:776)
> 
>        at
> com.alcatel.as.service.bundleinstaller.impl.BundleInstallerImpl.doScan(BundleInstallerImpl.java:664)
> 
>        at
> com.alcatel.as.service.bundleinstaller.impl.BundleInstallerImpl$1.run(BundleInstallerImpl.java:164)
> 
> 
> So, I guess here that CM may concurrently invoke both getDictionaries()
> and store(String pid, Dictionary dic) methods, and while enumerating the
> Enum returned by the getDictionaries() method, I then get the exception
> above ? In any case, I replaced replaced my Map with a ConcurrentHashMap
> and I don't have the exception anymore.


Probably yes - particularly in a situation where SCR is trying to find
configuration while another part is storing configuration.

> 
> 5) Now, with the ConcurrentHashMap version, I start my Felix. I have a
> demo appli which is something like the well known Dictionary OSGi demo:
> I have a SpellChecker and an EnglishDictionary.
> 
> The EnglishDictionary SCR descriptor is defined like this:
> -------------------------------------------------------------------------------------------------------------------------------------------
> 
> <?xml version="1.0" encoding="utf-8"?>
> <components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"; >
>  <scr:component name="englishdico" modified="updated"
> configuration-policy="require" immediate="true">
>    <service>
>      <provide interface="com.alcatel_lucent.dictionary.DictionaryService"/>
>    </service>
>    <property name="Language" value="en"/>
>    <implementation
> class="com.alcatel_lucent.dictionary.english.EnglishDictionary" />
>  </scr:component>
> </components>
> -------------------------------------------------------------------------------------------------------------------------------------------
> 
> 
> As you see, my EnglishDictionary component has a
> configuration-policy="require", meaning that the PID "englishdico"
> must be available before activating the englishdico component.
> 
> 6) But, during startup, I don't know if it's a race condition issue or
> not, but the englishdico component is not activated and I have the
> following log:
> 
> 2009-11-27 08:44:01,305 SCR Component Actor INFO  osgi config/ca -
> [englishdico] Missing required configuration, cannot activate
> 
> what I don't understand is that I have this log, but before the log, I
> see that the ConfigurationComponentRegistry.configurationEvent() method
> has been called with the proper "englishdico" PID
> So, I have modified the
> ConfigurationComponentRegistry.configurationEvent method in order to add
> more logs:
> 
> -------------------------------------------------------------------------------------------------------------------------------------------
> 
>    public void configurationEvent( ConfigurationEvent event )
>    {
>        final String pid = event.getPid();
>        final String factoryPid = event.getFactoryPid();
>              Activator.log( LogService.LOG_DEBUG, null, "Received
> Configuration Event pid=" + event.getPid() + "/type=" + event.getType(),
>                       null );
> 
>        final ComponentHolder cm;
>        if ( factoryPid == null )
>        {
>            cm = getComponent( pid );
>        }
>        else
>        {
>            cm = getComponent( factoryPid );
>        }
> 
>        if (cm == null) {
>          Activator.log( LogService.LOG_WARNING, null, "Component Holder
> is null for pid= " + event.getPid(),
>                         null );
>          return;
>        }
>              if (cm.getComponentMetadata().isConfigurationIgnored()) {
>          Activator.log( LogService.LOG_WARNING, null, "Component Holder
> ignores configuration for pid= " + event.getPid(),
>                         null );
>          return;
>        }
> -------------------------------------------------------------------------------------------------------------------------------------------
> 
> 
> 7) So, I start Felix, and then I have the following logs (SCR seems to
> catch the "englishdico" PID but it deos nothing, because the
> getComponent(pid) method returned null:
> 
> 2009-11-27 08:44:00,630 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [138] Scheduling task Update: pid=englishdico
> 2009-11-27 08:44:00,630 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Running task Update: pid=englishdico
> 2009-11-27 08:44:00,630 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Updating configuration englishdico to
> modification #2
> 2009-11-27 08:44:00,631 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Scheduling task Fire ConfigurationEvent:
> pid=englishdico
> 2009-11-27 08:44:00,631 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [138] Running task Fire
> ConfigurationEvent: pid=englishdico
> 2009-11-27 08:44:00,631 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - Received Configuration Event
> pid=englishdico/type=1
> 2009-11-27 08:44:00,631 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) WARN  osgi config/ca - Component Holder is null for
> pid= englishdico
> 
> 8) Therefore, next, I see that my "englishdico" is not activated:
> 
> 2009-11-27 08:44:00,632 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [138] UpdateConfiguration(englishdico) scheduled
> 2009-11-27 08:44:01,301 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] Component englishdico created: DS=1,
> implementation=com.alcatel_lucent.dictionary.english.EnglishDictionary,
> immediate=true, default-enabled=true, factory=null,
> configuration-policy=require, activate=activate, deactivate=deactivate,
> modified=updated
> 2009-11-27 08:44:01,301 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] Component englishdico Services:
> servicefactory=false,
> services=[com.alcatel_lucent.dictionary.DictionaryService]
> 2009-11-27 08:44:01,302 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] Component englishdico Properties: {Language=en}
> 2009-11-27 08:44:01,304 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] State transition : Disabled -> Enabling
> 2009-11-27 08:44:01,304 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] State transition : Enabling -> Unsatisfied
> 2009-11-27 08:44:01,304 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [englishdico] Component enabled
> 2009-11-27 08:44:01,305 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - Adding task [Enable Component: englishdico (10)] as #1 in
> the queue
> 2009-11-27 08:44:01,305 SCR Component Actor INFO  osgi config/ca -
> Running task: Enable Component: englishdico (10)
> 2009-11-27 08:44:01,305 SCR Component Actor DEBUG osgi config/ca -
> [englishdico] State transition : Unsatisfied -> Activating
> 2009-11-27 08:44:01,305 SCR Component Actor DEBUG osgi config/ca -
> [englishdico] Activating component
> 2009-11-27 08:44:01,305 SCR Component Actor INFO  osgi config/ca -
> [englishdico] Missing required configuration, cannot activate
> 
> And my englishdico is not activated because the PID is missing for my
> englishdico component, but this is not the case (see step 7)
> 
> 9) If I somehow re-update the "englishdico" by invoking my method
> populateCM("englishdico", dictionary) ... then my englishdico is finally
> properly activated:
> 
> 2009-11-27 08:44:28,439 ProxyAppReporter-FastCacheListener DEBUG osgi
> config/ca - [138] Scheduling task Update: pid=englishdico
> 2009-11-27 08:44:28,440 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Running task Update: pid=englishdico
> 2009-11-27 08:44:28,440 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Updating configuration englishdico to
> modification #3
> 2009-11-27 08:44:28,440 Configuration Updater (Update: pid=englishdico)
> DEBUG osgi config/ca - [138] Scheduling task Fire ConfigurationEvent:
> pid=englishdico
> 2009-11-27 08:44:28,440 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [138] Running task Fire
> ConfigurationEvent: pid=englishdico
> 2009-11-27 08:44:28,440 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - Received Configuration Event
> pid=englishdico/type=1
> 2009-11-27 08:44:28,442 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [englishdico] State transition :
> Unsatisfied -> Activating
> 2009-11-27 08:44:28,443 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [englishdico] Activating component
> 2009-11-27 08:44:28,446 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [englishdico] getting activate:
> activate
> 2009-11-27 08:44:28,446 Configuration Updater (Fire ConfigurationEvent:
> pid=englishdico) DEBUG osgi config/ca - [englishdico] invoking activate:
> activate
> 
> So, my question is:
> 
>       1) Is there a problem with my "MapPersistenceManager"
> implementation: Am I doing something very bad here ?
>       2) Or is there a race condition in SCR ?

The best thing to crosscheck these questions is to use the default
persistence manager for a test. If this works, chances are that there is
a race condition inside your MapPersistenceManager (maybe even related
to the use of the ConcurrentHashMap ..)


Regards
Felix

> 
> thanks for your help;
> /pierre
> 
> 

Reply via email to