Hello everyone;
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.
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.
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 ?
thanks for your help;
/pierre
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.