Require a service to be active before a bundle is started

Require a service to be active before a bundle is started



I have written a BundleActivator which should update certain configurations before its bundle starts. I need the ConfigurationAdmin service, but I get a null ServiceReference from the BundleContext in the start method of the BundleActivator.



The BundleActivator extends following abstract class and only implements the specific update logic:


public abstract class AbstractConfigUpdater implements BundleActivator

private ServiceReference<ConfigurationAdmin> configurationAdminServiceReference;

@Override
public void start(final BundleContext context) throws Exception
configurationAdminServiceReference = context.getServiceReference(ConfigurationAdmin.class);
final ConfigurationAdmin configurationAdmin = context.getService(configurationAdminServiceReference);
final Configuration configurations =
configurationAdmin.listConfigurations(getFilter());
if (configurations != null)
for (final Configuration configuration : configurations)
final Dictionary<String, Object> properties = configuration.getProperties();
if (updateProperties(properties))
configuration.update(properties);





protected abstract String getFilter();

/**
* Updates the properties if needed.
*
* @param properties
* the configuration properties
* @return if any modifications to the Dictionary were made
*/
protected abstract boolean updateProperties(final Dictionary<String, Object> properties);

@Override
public void stop(final BundleContext context) throws Exception
context.ungetService(configurationAdminServiceReference);





I have added an annotation to the concrete BundleActivator to generate a manifest header to require the ConfigurationAdmin service to be available to the bundle:


@RequireCapability(filter = "(objectClass=org.osgi.service.cm.ConfigurationAdmin)",
ns = "osgi.service",
resolution = Resolution.mandatory)



The manifest header is generated, but I still get a null ServiceReference. How should I fix this? Or is there an alternative approach I could take to update configurations before their components are started?





Is there any reason at all not use Declarative Services (DS)? The problem you're trying to solve is really hard in an Activator but trivial in DS.
– Peter Kriens
Aug 30 at 10:12





You also confuse static dependencies (Require-Capability) with dynamic dependencies (this bundle should be active). They are two different things and unrelated. The Require Capability ensures there is a bundle installed but there is no guarantee that the service is registered since this can depend on other things.
– Peter Kriens
Aug 30 at 10:14





Thanks for the clarification on Require-Capability. The reason I chose a BundleActivator instead of a DS component, is that I want to update configurations on bundle startup, as the ObjectClassDefinition of the configurations has changed and I want to run the configuration update before activation of the corresponding DS components.
– Auke te Winkel
Aug 30 at 11:00






Did you look at the OSGi Configurer in R7? (Or its predecessor in v2archive.osgi.enroute/osgi.enroute.configurator.simple.provider). That might solve your problems in an easier way. The way you're going now is a rabbit hole.
– Peter Kriens
Aug 30 at 16:06




2 Answers
2



I don't know if this could help, but you can develop a org.osgi.service.cm.ConfigurationPlugin to intercept all the properties that are injected at runtime and modify them:


org.osgi.service.cm.ConfigurationPlugin


public class MyConfigurationPlugin implements BundleActivator, ConfigurationPlugin
ServiceRegistration<ConfigurationPlugin> configPluginRef;

@Override
public void start(BundleContext context) throws Exception
//... init the config plugin
Map<String,String> properties = new HashMap<>();
configPluginRef = context.registerService(
ConfigurationPlugin.class,
this,
new Hashtable<>(properties));


@Override
public void modifyConfiguration(ServiceReference<?> reference,
Dictionary<String, Object> properties)
/*
* View and possibly modify a set of configuration properties
* before they are sent to the Managed Service or the Managed Service Factory.
*/





Of course the Declarative Service approach is a way far simpler option:


@Component (
service= ,
configurationPid=
configPid1,
configPid2,
...
)
public class MyComponent

@Activate
public void activate(BundleContext context, Map<String, String> properties)



@Modified
public void updated(BundleContext context, Map<String, String> properties)
// Called when properties change




but in this case you cannot alter properties values: you can only react to properties changes.



You can use OSGi ServiceTracker to wait and retrieve the service from the service registry.



For example,


import org.osgi.framework.Constants
import org.osgi.framework.Filter;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.service.cm.ConfigurationAdmin;

...

private static final long TIMEOUT_MILLIS = 10000;

@Override
public void start(final BundleContext context) throws Exception
Filter filter = context.createFilter("(" + Constants.OBJECTCLASS + "=org.osgi.service.cm.ConfigurationAdmin)");
ServiceTracker<?, ?> configurationAdminTracker = new ServiceTracker<>(context, filter, null);

configurationAdminTracker.open();
ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) configurationAdminTracker.waitForService(TIMEOUT_MILLIS);
configurationAdminTracker.close();

if (configurationAdmin == null)
// Not found

...



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)