我正在开发一个构建在Apache Felix和JavaFX之上的应用程序。应用程序可以通过实现特定接口的第三方软件包进行扩展,并使其可供OSGi运行时服务注册表使用。
问题是那些捆绑包(或插件)不应该能够检索我的应用程序内部使用的任何服务。一个示例是PersistenceService,用于保存已处理的数据。根据定义,插件(在我的应用程序中)不允许通过我的服务存储任何数据,但允许通过仅为插件设计的特定服务来保存它们。
我有想法使用OSGi提供的FindHook接口来过滤掉那些请求但是效果不好。显然,为了使它工作,捆绑包需要在我的核心应用程序加载之前一开始就加载。我通过使用felix.auto.deploy.install.1 = "file\:bundles/de/zerotask/voices-findhook/0.1-SNAPSHOT/voices-findhook-0.1-SNAPSHOT.jar"
据我所知,系统包的启动级别为1,这意味着我的包应该始终在系统包之后加载。
这是我对FindHook界面的实现:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.hooks.service.FindHook;
/**
*
* @author PositiveDown
*/
public class VoicesFindHook implements FindHook {
private static Logger log = LoggerFactory.getLogger(VoicesFindHook.class);
private static final String[] INTERNAL_BUNDLE_TABLE = new String[]{
"de.zerotask.voices-core-actions",
"de.zerotask.voices-findhook",
"de.zerotask.voices-interfaces-persistable",
"de.zerotask.voices-models",
"de.zerotask.voices-models-actions",
"de.zerotask.voices-services-configuration-internal",
"de.zerotask.voices-services-input-internal",
"de.zerotask.voices-services-licenses-internal",
"de.zerotask.voices-services-modelsmanager-internal",
"de.zerotask.voices-services-persistence-internal",
"de.zerotask.voices-services-window-internal",
"de.zerotask.voices-ui-dialogs-about",
"de.zerotask.voices-ui-dialogs-newprofile",
"de.zerotask.voices-ui-dockable-listview",
"de.zerotask.voices-ui-dockable-properties",
"de.zerotask.voices-ui-layout",
"de.zerotask.voices-utils-io",
"de.zerotask.voices-utils-services",
"de.zerotask.voices-utils-ui"
};
private static final String[] INTERNAL_SERVICES_TABLE = new String[]{
// model services
// configuration service
"de.zerotask.voices.services.configuration.IConfiguration",
// window service
"de.zerotask.voices.services.window.IWindowService",
// persistence services
"de.zerotask.voices.services.persistence.IPathResolver",
"de.zerotask.voices.services.persistence.IPersistenceService"
};
private static final Set<String> INTERNAL_BUNDLES = new HashSet<>(Arrays.asList(INTERNAL_BUNDLE_TABLE));
private static final Set<String> INTERNAL_SERVICES = new HashSet<>(Arrays.asList(INTERNAL_SERVICES_TABLE));
@Override
public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references) {
// only allow the usage of internal interfaces from internal packages
String symbolicName = context.getBundle().getSymbolicName();
// debug
log.debug("Processing Bundle {} and service {}", symbolicName, name);
// if the service is one of the internal ones, proceed
if (INTERNAL_SERVICES.contains(name)) {
// retrieve the bundle id
log.debug("Service {} is in internal table", name);
// if the name is not in the internal bundle table, remove all service references
if (!INTERNAL_BUNDLES.contains(symbolicName)) {
log.debug("Bundle {} not in internal table => removing service references...", symbolicName);
// remove them
references.clear();
}
}
}
}
我们的想法是建立一个internal bundles``` and
内部服务``的表。每次查询服务时,挂钩都会检查它是否是内部服务。如果是这种情况,它还将检查调用者包是否是内部包。如果不是这样,那么钩子将删除从集合中找到的所有服务。
到目前为止,我还没有OSGi专家,但这种方法应该有效,因为它基于每个容器中唯一的SymbolicName
。
我用两个小测试包测试了上面的代码。一个提供接口+实现,另一个使用它。我更改了钩子,因此它不会为消费者包返回任何服务(只是简单地检查它是否有效)。
不,我的问题是,消费者包首先以某种方式加载。我不知道为什么。通过这样做,它基本上破坏了我在属性文件中设置的加载属性。 我不确定这是否有帮助,但提供者包的名称以'y'开头,消费者名称以't'开头,钩子名称以'v'开头。 有趣的是,Felix按字母顺序加载它们。
我真的很感激这里的任何帮助。
答案 0 :(得分:3)
每个捆绑包都隐含地提供服务 - 毕竟这是服务的目的。
您可以使用FindHooks等各种黑客来解决这个问题,但正如您已经发现的那样,您经常与OSGi框架和服务的真实性质作斗争。
这听起来更像是在内核和用户空间之间创建隔离系统,因此您不会意外地使用内核服务污染用户区域,而反之亦然。实现这一目标的正确方法(恕我直言)是针对这两个领域的单独OSGi框架实例。使用FrameworkFactory
API运行新框架非常简单。然后,您可以使用用户区框架的系统包的BundleContext
公开内核中的选择包和服务。
然而正如BJ在评论中指出的那样,你可能会过度设计这个。如果插件可以看到您的系统服务,最糟糕的情况是什么?如果这些服务设计得很好,那么答案应该是“不是很多”。
答案 1 :(得分:-1)