Hi Pierre,

Thanks for the feedback.

Regards
Felix

Pierre De Rop schrieb:
> Hi Felix,
> 
> The problem comes from my side ! I was not cloning dictionaries in my
> PersistentManager getters/setters method
> So, I closed the issue (see my comments in it).
> 
> Regards;
> /pierre
> 
> 
> Felix Meschberger wrote:
>> 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