java - 如何隐藏 OSGi 服务以使其他 bundle 无法找到它们?

标签 java javafx osgi osgi-bundle

我正在开发一个基于 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/

相关文章:

java - 强制导入 OSGi 包

java - 私有(private)方法上的@Transactional 传播

java - 读取文本文件时出现问题

java - 是否有其他方法可以使用 Class.forName() 加载类?

html - 在 JavaFX WebView 中检测 HTML textarea onkeyup 事件

java - 如何使用 EventHandler<MouseEvent> 在舞台上加载图像?

java - 从 OSGI bundle 调用 JDBC 和 UCP 连接

java - 列出被调用的方法的名称

java - 证书与私钥匹配

java - 为什么 javafx 忽略 main 的返回并仍然启动应用程序?