【问题标题】:OSGI: Service not available after Bundle updateOSGI:捆绑更新后服务不可用
【发布时间】:2013-10-07 09:15:24
【问题描述】:

我有一个 Bundle P(rovider= 它实现了在 Bundle I(interface) 中定义的接口 Bundle U(ser) 应该使用这个服务。在我启动应用程序后一切正常,我的所有服务都可以使用。但是当我更新了Bundle P,没有一个服务可以解决。

更新方法如下:

this._bundle.stop();
this._bundle.update(new FileInputStream(updateFile));
this._bundle.start();

这是我的所有包的 BundleActivator,它也应该处理 ServiceRegistrations 和 ServiceReferences:

public abstract class BundleActivator implements org.osgi.framework.BundleActivator, BundleListener, ServiceListener
{
/**
 * Bundle Context.
 */
protected BundleContext context;

/**
 * Services which are registered by this bundle.
 */
protected HashSet<ServiceRegistration> serviceRegistrations = new HashSet<ServiceRegistration>();

/**
 * Service references used by this bundle.
 */
protected HashMap<String, ServiceReference> serviceReferences = new HashMap<String, ServiceReference>();

/**
 * Perform this method after Bundle has started.
 *
 * @param bc BundleContext.
 */
protected abstract void afterStart(BundleContext bc);

/**
 * Perform this method before Bundle is going to be stoped.
 *
 * @param bc BundleContext.
 */
protected abstract void beforeStop(BundleContext bc);

/**
 * Perform this method after Bundle has changed.
 *
 * @param be BundleEvent
 */
protected abstract void afterBundleChanged(BundleEvent be);

/**
 * Returns the bundle context for this bundle.
 *
 * @return bundle context
 */
public BundleContext getContext() {
    return this.context;
}

/**
 * Registeres a service.
 *
 * @param clazz      interface
 * @param service    service
 * @param properties properties
 *
 * @return service registration
 */
public ServiceRegistration registerService(Class clazz, Object service, Dictionary<String, ?> properties) {
    return this.registerService(clazz.getCanonicalName(), service, properties);
}

/**
 * Registeres a service.
 *
 * @param clazz      interface
 * @param service    service
 * @param properties properties
 *
 * @return service registration
 */
public ServiceRegistration registerService(String clazz, Object service, Dictionary<String, ?> properties) {
    ServiceRegistration retval = this.context.registerService(clazz, service, properties);
    System.out.println("registered service: " + retval.toString() + " for " + clazz);
    this.serviceRegistrations.add(retval);
    return retval;
}

/**
 * Returns a registered service.
 *
 * @param clazz interface
 *
 * @return service instance
 */
public Object getService(Class clazz) {
    if (clazz == null) {
        return null;
    }
    return this.getService(clazz.getCanonicalName());
}

/**
 * Returns a registered service.
 *
 * @param clazz interface
 *
 * @return service instance
 */
public Object getService(String clazz) {
    if (clazz == null) {
        return null;
    }
    System.out.println("Class: " + clazz);
    ServiceReference sr = this.context.getServiceReference(clazz);
    System.out.println("SR: " + sr);
    if (sr == null) {
        if (this.serviceReferences.containsKey(clazz)) {
            System.out.println("Unget service");
            this.context.ungetService(this.serviceReferences.get(clazz));
            this.serviceReferences.remove(clazz);
        }
        sr = this.context.getServiceReference(clazz);
        System.out.println("SR: " + sr);
        if (sr == null) {
            return null;
        }
    }

    try {
        this.context.addServiceListener(this, "(objectClass=" + clazz + ")");
    } catch (InvalidSyntaxException ex) {
        Logger.getLogger(BundleActivator.class.getName()).log(Level.SEVERE, null, ex);
    }

    this.serviceReferences.put(clazz, sr);
    return this.context.getService(sr);
}

@Override
public void start(BundleContext bc) throws Exception {
    ContextRegistry.getInstance().add(bc);

    this.context = bc;
    this.context.addBundleListener(this);
    this.afterStart(bc);
    System.out.println("Balindoo bundle activated: " + this.getClass().getPackage().getName());
}

@Override
public void stop(BundleContext bc) throws Exception {
    this.beforeStop(bc);

    for (ServiceRegistration sr : this.serviceRegistrations) {
        this.context.ungetService(sr.getReference());
        sr.unregister();
    }
    this.serviceRegistrations.clear();

    for (ServiceReference sr : this.serviceReferences.values()) {
        this.context.ungetService(sr);
    }
    this.serviceReferences.clear();

    ContextRegistry.getInstance().remove(bc);
    this.context.removeBundleListener(this);
    this.context = null;
    System.out.println("Balindoo bundle deactivated: " + this.getClass().getPackage().getName());
}

@Override
public void bundleChanged(BundleEvent be) {
    String name = be.getBundle().getSymbolicName();
    if (name.startsWith("com.vaadin")) {
        if (be.getType() == BundleEvent.STARTED && !ResourceProvider.getInstance().hasBundle(be.getBundle())) {
            ResourceProvider.getInstance().add(be.getBundle());
        } else if (be.getType() == BundleEvent.STOPPED && ResourceProvider.getInstance().hasBundle(be.getBundle())) {
            ResourceProvider.getInstance().remove(be.getBundle());
        }
    }

    for (ServiceReference sr : this.serviceReferences.values()) {
        this.context.ungetService(sr);
    }
    this.serviceReferences.clear();

    HashSet<Bundle> thisBundle = new HashSet<>();
    thisBundle.add(this.context.getBundle());
    thisBundle.add(be.getBundle());

    FrameworkWiring wiring = this.context.getBundle().adapt(FrameworkWiring.class);
    if (wiring != null) {
        System.out.println("FrameworkWiring:\n\tthis:\t" + this.context.getBundle().getSymbolicName() + "\n\tto  :\t" + be.getBundle().getSymbolicName());
        wiring.refreshBundles(thisBundle);
    }

    this.afterBundleChanged(be);
}

@Override
public void serviceChanged(ServiceEvent event) {
    switch (event.getType()) {
        case ServiceEvent.UNREGISTERING:
            System.out.println("unregister service");
            if (this.serviceReferences.containsValue(event.getServiceReference())) {
                //Remove
            }
            this.context.ungetService(event.getServiceReference());
            break;
    }
}

如您所见,我尝试了很多来解决这个问题,但没有任何效果。 我做错了什么?

这是捆绑包 P (org.company.example.data) 的清单。该接口位于单独的包中的 org.company.example.data.api 中。

Manifest-Version: 1.0
Bnd-LastModified: 1381157007428
Build-Jdk: 1.7.0_21
Built-By: nspecht
Bundle-Activator: org.company.example.data.impl.BundleActivator
Bundle-Description: Example Bundle org.company.example.data 1.0.0
Bundle-ManifestVersion: 2
Bundle-Name: org.company.example.data
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-SymbolicName: org.company.org.company.example.data
Bundle-Vendor: Company Inc.
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Eclipse-BuddyPolicy: registered
Eclipse-RegisterBuddy: org.company.wrapper.hibernate
Export-Package: org.company.example.data.api;uses:="org.company.example.data.api.model";version="1.0.0",org.company.example.data.impl;uses:="org.company.example.data.api,org.company.utils.data.database,org.osgi.framework,org.company.example.data.api.model,org.company.utils.modulemanager.generic,org.hibernate,org.hibernate.criterion";version="1.0.0",org.company.example.data;version="1.0.0",org.company.example.data.api.impl;uses:="org.osgi.framework,org.company.utils.modulemanager.generic";version="1.0.0",org.company.example.data.api.model;uses:="org.company.utils.data.api";version="1.0.0",org.company.example.data.i18n;version="1.0.0"
Import-Package: org.company.utils.data.api;version="[1.0,2)",org.company.utils.data.database;version="[1.0,2)",org.company.utils.modulemanager.generic;version="[1.0,2)",org.hibernate;version="4.2,5)",org.hibernate.criterion;version="4.2,5)",org.osgi.framework;version="[1.6,2)"
Tool: Bnd-1.50.0

接口包的清单:

Manifest-Version: 1.0
Bnd-LastModified: 1381156992131
Build-Jdk: 1.7.0_21
Built-By: nspecht
Bundle-Activator: org.company.example.data.api.impl.BundleActivator
Bundle-Description: Example Bundle org.company.example.data.api 1.0.0
Bundle-ManifestVersion: 2
Bundle-Name: org.company.example.data.api
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-SymbolicName: org.company.org.company.example.data.api
Bundle-Vendor: Company Inc.
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Eclipse-BuddyPolicy: registered
Export-Package: org.company.example.data.api;uses:="org.company.example.data.api.model";version="1.0.0",org.company.example.data.api.impl;uses:="org.osgi.framework,org.company.utils.modulemanager.generic";version="1.0.0",org.company.example.data.api.model;uses:="org.company.utils.data.api";version="1.0.0"
Import-Package: org.company.utils.data.api;version="[1.0,2)",org.company.utils.modulemanager.generic;version="[1.0,2)",org.osgi.framework;version="[1.6,2)"
Tool: Bnd-1.50.0

至少是 Bundle U 的接口:

Manifest-Version: 1.0
Bnd-LastModified: 1381157008373
Build-Jdk: 1.7.0_21
Built-By: nspecht
Bundle-Activator: org.company.example.webui.impl.BundleActivator
Bundle-Description: Example Bundle org.company.example.webui 1.0.0
Bundle-ManifestVersion: 2
Bundle-Name: org.company.example.webui
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-SymbolicName: org.company.org.company.example.webui
Bundle-Vendor: Company Inc.
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Eclipse-BuddyPolicy: registered
Export-Package: org.company.example.webui.impl;uses:="org.company.utils.webui,org.company.example.data.api,org.company.example.webui.menu,org.osgi.framework,org.company.utils.webui.menu,org.company.example.webui.view,org.company.utils.modulemanager.generic,org.company.utils.modulemanager.exception";version="1.0.0",org.company.example.webui.menu;uses:="org.company.utils.webui,org.company.utils.webui.generics,org.company.utils.modulemanager.translation,org.company.example.webui.view,org.company.utils.webui.menu";version="1.0.0",org.company.example.webui.i18n;version="1.0.0",org.company.example.webui.view;uses:="org.company.example.data.api,com.vaadin.server,org.company.utils.modulemanager.translation,org.company.example.data.api.model,com.vaadin.ui,org.company.example.webui.impl,com.vaadin.event,org.company.utils.webui.exception,com.vaadin.data,com.vaadin.data.util,com.vaadin.navigator,org.company.utils.modulemanager.exception";version="1.0.0"
Import-Package: com.vaadin.data;version="[7.1,8)",com.vaadin.data.util;version="[7.1,8)",com.vaadin.event;version="[7.1,8)",com.vaadin.navigator;version="[7.1,8)",com.vaadin.server;version="[7.1,8)",com.vaadin.ui;version="[7.1,8)",org.company.example.data.api;version="[1.0,2)",org.company.example.data.api.model;version="[1.0,2)",org.company.utils.modulemanager.exception;version="[1.0,2)",org.company.utils.modulemanager.generic;version="[1.0,2)",org.company.utils.modulemanager.translation;version="[1.0,2)",org.company.utils.webui;version="[1.0,2)",org.company.utils.webui.exception;version="[1.0,2)",org.company.utils.webui.generics;version="[1.0,2)",org.company.utils.webui.menu;version="[1.0,2)",org.osgi.framework;version="[1.6,2)"
Tool: Bnd-1.50.0

【问题讨论】:

    标签: osgi updates equinox osgi-bundle


    【解决方案1】:

    检查谁在导出包含服务接口 I 的包。P 和 U 必须连接到同一个包。为了确保 U 可以使用服务对象,框架会验证 U 是否连接到与 P 相同的包。

    似乎在更新 P 之后,新的 P' 被连接到与 U 不同的包的不同版本。所以当 P' 注册服务时,它来自包的不同版本。

    如果包包含在 P 中并由 P 导出,而 P 也导入相同的包,则可能会发生这种情况。服务提供者应该同时导出和导入服务接口包。见http://blog.osgi.org/2007/04/importance-of-exporting-nd-importing.html

    【讨论】:

    • 我的包P正在导入导出Interface所在的包。
    • 你的意思是你的包 P 正在导入和导出包。也许你可以分享清单?您应该确保更新后 Bundle P 和 Bundle U 连接到服务接口的同一个包。
    • 我更新了 3 个 MANIFEST.MF 文件。我在之前的帖子中犯了一个错误。 Bundle P是-NOT-导入接口所在的Bundle。我将它添加为依赖项,并告诉 maven 导出每个名为 org.company.example.data.* 的包(实际上包括 org.company.example.data.api)。这是我的错吗?
    • 在更改捆绑包和包名称后它可以工作。感谢您的提示。
    【解决方案2】:

    您很可能还需要“刷新”您的消费包 (U),因为通常消费包保留对原始包 P 的引用,因此它不会看到您的新服务。所以你需要把你的bundle U 带回“resolving”状态。在 GOGO shell 中,您通常只需发出刷新命令。

    【讨论】:

    • 调用刷新命令,无济于事。我也尝试停止和启动 U,但它也不起作用
    猜你喜欢
    • 2021-04-04
    • 1970-01-01
    • 2014-12-21
    • 2014-04-23
    • 2020-07-27
    • 2013-10-31
    • 1970-01-01
    • 2011-01-01
    • 2015-01-12
    相关资源
    最近更新 更多