我正在开发一个基于 Apache Felix 和 JavaFX 构建的应用程序。该应用程序可以通过实现特定接口(interface)的第三方 bundle 进行扩展,并使其可供 OSGi 运行时服务注册表使用。
问题是这些 bundle (或插件)不应该能够检索我的应用程序内部使用的任何服务。一个例子是用于保存处理后的数据的 PersistenceService。根据定义,插件(在我的应用程序中)不允许通过我的服务存储任何数据,但允许通过仅为插件设计的特定服务来保存它们。
我曾想过使用 OSGi 提供的 FindHook 接口(interface)来过滤掉这些请求,但效果并不好。显然,为了使其工作,我需要在一开始就加载该 bundle ,甚至在加载我的核心应用程序之前。我通过使用 felix.auto.deploy.install.1 = "file\:bundles/de/zerotask/voices-findhook/0.1-SNAPSHOT/voices-findhook-0.1-SNAPSHOT.jar"
指定该 bundle 的启动级别来确保发生这种情况。
据我了解,系统 bundle 的启动级别将为 1,这意味着我的 bundle 应始终在系统 bundle 之后加载。
这是我对 FindHook 接口(interface)的实现:
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
内部服务```。每次查找服务时, Hook 都会检查它是否是内部服务。如果是这种情况,它还会检查调用者包是否是内部包。如果不是这样, Hook 将删除从集合中找到的所有服务。
到目前为止,我不是 OSGi 专家,但此方法应该有效,因为它基于 SymbolicName
每个容器中都是唯一的。
我已经用两个小测试包测试了上面的代码。一种提供接口(interface)+实现,另一种使用它。我更改了 Hook ,因此它不会为消费者 bundle 返回任何服务(只是简单地检查它是否有效)。
不,我的问题是,消费者包以某种方式首先加载。我不知道为什么。通过这样做,它基本上破坏了我在属性文件中设置的加载属性。 我不确定这是否有帮助,但提供者 bundle 的名称以“y”开头,消费者 bundle 的名称以“t”开头, Hook bundle 的名称以“v”开头。 有趣的是,Felix 按字母顺序加载它们。
我非常感谢这里的任何帮助。
最佳答案
服务对每个包都是隐式可用的——这毕竟是服务的目的。
您可以使用 FindHooks 等各种技巧来解决这个问题,但正如您已经发现的那样,您一直在与 OSGi 框架和服务的真实本质作斗争。
这听起来更像是您在内核和用户空间之间创建一个隔离系统,这样您就不会意外地用内核服务污染用户区域,反之亦然。实现这一点的正确方法(恕我直言)是为这两个区域使用单独的 OSGi 框架实例。使用 FrameworkFactory
API 运行新框架非常简单。然后,您可以使用用户区域框架的系统 bundle 的 BundleContext
从内核公开选定的包和服务。
然而,正如 BJ 在评论中指出的那样,您可能对此进行了过度设计。如果插件可以看到您的系统服务,最糟糕的情况是什么?如果这些服务设计得很好,那么答案应该是“不是很多”。
关于java - 如何隐藏 OSGi 服务以使其他 bundle 无法找到它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36310146/