OSGi force bundle start twice with different configurations
apache-felix, osgi
Solution
Using Factory Configurations would allow you to create different instances of FooImpl based on different configurations.
For example in Declarative Services you can create a component like
import org.apache.felix.scr.annotations.*;
import org.apache.sling.commons.osgi.PropertiesUtil;
@Component(metatype = true,
name = FooImpl.SERVICE_PID,
configurationFactory = true,
specVersion = "1.1",
policy = ConfigurationPolicy.REQUIRE)
public class FooImpl implements IFoo
{
//The PID can also be defined in interface
public static final String SERVICE_PID = "com.foo.factory";
private static final String DEFAULT_BAR = "yahoo";
@Property
private static final String PROP_BAR = "bar";
@Property(intValue = 0)
static final String PROP_RANKING = "ranking";
private ServiceRegistration reg;
@Activate
public void activate(BundleContext context, Map<String, ?> conf)
throws InvalidSyntaxException
{
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put("type", PropertiesUtil.toString(config.get(PROP_BAR), DEFAULT_BAR));
props.put(Constants.SERVICE_RANKING,
PropertiesUtil.toInteger(config.get(PROP_RANKING), 0));
reg = context.registerService(IFoo.class.getName(), this, props);
}
@Deactivate
private void deactivate()
{
if (reg != null)
{
reg.unregister();
}
}
}
Key points here being
- You use a component of type `configurationFactory`
- In the activate method you read the config and then based on that register a service
- In deactivate you explicitly unregister the service
- End users would then create config file with name `<pid>-<some name>.cfg`. Then DS would then activate the component.
Then you can create multiple instances by creating configuration (using File Install like) file with name `<pid>-<some name>.cfg` like `com.foo.factory-type1.cfg`
Refer to JdbcLoginModuleFactory and its associated config for one such example.
If you want to achieve the same via plain OSGi then you need to register a ManagedServiceFactory. Refer to JaasConfigFactory for one such example.
Key points here being
- You register a ManagedServiceFactory instance with configuration PID as the service property
- In the ManagedServiceFactory(String pid, Dictionary properties) callback register instances of FooImpl based on the config properties
Problem
I'm using embedded Felix in my application. Application can potentially deal with lot of plugins that exposes similar interface `IFoo`. There is default an implementation `FooImpl` Hopefully for most plugins default `FooImpl` can be used with specific configuration files. I would like dynamically install and start the same bundle (with `FooImpl`) when new configuration file appears. I've reviewed already FileInstall but have no idea how to apply it there. UPDATE: Deployment sequence. The jar containing `FooImpl` and `IFoo` is stable, but I need hot-deploy of new instances that are result of uploading new .cfg file to scope of FileInstall. So desired is very simple - user uploads .cfg, new service (instance of `FooImpl`) is appeared.