OSGI:Bundle更新后服务不可用

时间:2013-10-07 09:15:24

标签: osgi updates equinox osgi-bundle

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

更新方法如下所示:

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

这是我的所有Package的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

至少捆绑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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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