开始捆绑之前,要求服务处于活动状态

时间:2018-08-30 09:08:04

标签: osgi

我写了一个BundleActivator,它应该在捆绑开始之前更新某些配置。我需要ConfigurationAdmin服务,但是在BundleActivator的start方法中,我从BundleContext获得了空的ServiceReference。

BundleActivator扩展了以下抽象类,并且仅实现了特定的更新逻辑:

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);
    }

}

我已经在具体的BundleActivator中添加了注释,以生成清单标头,以要求ConfigurationAdmin服务可用于该包:

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

清单头已生成,但是我仍然得到一个空的ServiceReference。我该如何解决?还是有其他方法可以在启动组件之前更新配置?

2 个答案:

答案 0 :(得分:0)

我不知道这是否有帮助,但是您可以开发一个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.  
         */
    }

}

当然,声明式服务方法是一种更简单的选择:

@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
    }
}

但是在这种情况下,您不能更改属性值:您只能对属性更改做出反应。

答案 1 :(得分:0)

您可以使用OSGi ServiceTracker等待并从服务注册表中检索服务。

例如,

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
    }
    ...
}