Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSGi force bundle start twice with different configurations

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.

like image 975
Dewfy Avatar asked Feb 17 '23 21:02

Dewfy


1 Answers

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

  1. You use a component of type configurationFactory
  2. In the activate method you read the config and then based on that register a service
  3. In deactivate you explicitly unregister the service
  4. 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

  1. You register a ManagedServiceFactory instance with configuration PID as the service property
  2. In the ManagedServiceFactory(String pid, Dictionary properties) callback register instances of FooImpl based on the config properties
like image 167
Chetan Avatar answered Mar 03 '23 14:03

Chetan