Требовать, чтобы служба была активна до запуска пакета - PullRequest
0 голосов
/ 30 августа 2018

Я написал BundleActivator, который должен обновить определенные конфигурации перед запуском его пакета. Мне нужен сервис ConfigurationAdmin, но я получаю нулевую ServiceReference из BundleContext в методе запуска BundleActivator.

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 голосов
/ 04 сентября 2018

Вы можете использовать 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
    }
    ...
}
0 голосов
/ 01 сентября 2018

Я не знаю, может ли это помочь, но вы можете разработать 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
    }
}

но в этом случае вы не можете изменять значения свойств: вы можете реагировать только на изменения свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...