如何隐藏OSGi服务以便其他捆绑包找不到它们?

时间:2016-03-30 13:21:57

标签: java javafx osgi osgi-bundle

我正在开发一个构建在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按字母顺序加载它们。

我真的很感激这里的任何帮助。

2 个答案:

答案 0 :(得分:3)

每个捆绑包都隐含地提供服务 - 毕竟这是服务的目的。

您可以使用FindHooks等各种黑客来解决这个问题,但正如您已经发现的那样,您经常与OSGi框架和服务的真实性质作斗争。

这听起来更像是在内核和用户空间之间创建隔离系统,因此您不会意外地使用内核服务污染用户区域,而反之亦然。实现这一目标的正确方法(恕我直言)是针对这两个领域的单独OSGi框架实例。使用FrameworkFactory API运行新框架非常简单。然后,您可以使用用户区框架的系统包的BundleContext公开内核中的选择包和服务。

然而正如BJ在评论中指出的那样,你可能会过度设计这个。如果插件可以看到您的系统服务,最糟糕的情况是什么?如果这些服务设计得很好,那么答案应该是“不是很多”。

答案 1 :(得分:-1)

我看到两个选项:

  • ServiceFactory,您决定什么捆绑可以获得真正的服务。其他人收到假实施。