我写了一个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。我该如何解决?还是有其他方法可以在启动组件之前更新配置?
答案 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
}
...
}