【问题标题】:bundle.update() from another bundle fails来自另一个包的 bundle.update() 失败
【发布时间】:2013-02-25 13:23:28
【问题描述】:

我正在构建一个简单的 OSGi 演示应用程序来了解该框架。我想从另一个包中更新一个活动包,或者从一个嵌入了 OSGi 框架的应用程序(如How To Embed OSGi by Neil Bartlett 中所述)。

我的应用程序被分成这些包(我已将代码放在帖子末尾以便于阅读):

  1. com.dc.sszostek.interfaces - 包含一个带有 draw() 方法的 Shape 接口
  2. com.dc.sszostek.implementations - 有 2 个带有此 SymbolicName 的包,每个包都实现了 Shape 接口:println 是一个 Line,另一个是 Square。它们的两个清单文件都是相同的,只是捆绑包的实现不同。
  3. com.dc.sszostek.programs - 包含一个 Painter 程序;它使用Shape接口来draw()(我用OSGi Services - Tutorial by Lars Vogel写的)。
  4. com.dc.sszostek.xmpp - 包含使用 SmackAPI 实现的 Jabber 客户端,等待文件传输并在收到文件时尝试更新 com.dc.sszostek.implementations 包。

我的问题是,当我向我的应用程序发送不同的实现时,文件被写入,但捆绑包没有得到更新。

bundle.update() 被调用,它不会抛出异常,但我的程序会一直画一条线(或正方形,取决于我首先放入的包)。当我从 OSGi 控制台更新包时,它会被正确替换,并且我的演示开始绘制不同的形状。

谁能告诉我我犯的错误在哪里,或者指出一个可行的例子?

提前谢谢你。


com.dc.sszostek.interfaces

清单.MF

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: Provider
    Bundle-SymbolicName: com.dc.sszostek.interfaces
    Bundle-Version: 1.0.0
    Export-Package: com.dc.sszostek.interfaces

Shape.java

    package com.dc.sszostek.interfaces;

    public interface Shape {
        void draw();
    }

com.dc.sszostek.implementations

清单.MF

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: Impl
    Bundle-SymbolicName: com.dc.sszostek.implementations
    Bundle-Version: 1.0.0
    Bundle-Activator: com.dc.sszostek.implementations.Activator
    Export-Package: com.dc.sszostek.implementations
    Import-Package: org.osgi.framework, com.dc.sszostek.interfaces

Activator.java

    package com.dc.sszostek.implementations;

    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import com.dc.sszostek.interfaces.Shape;

    public class Activator implements BundleActivator {

        public void start(BundleContext ctx) throws Exception {
            ctx.registerService(Shape.class.getName(), new Line(), null);
        }

        public void stop(BundleContext ctx) throws Exception {}
    }

Line.java

    package com.dc.sszostek.implementations;

    import com.dc.sszostek.interfaces.Shape;

    public class Line implements Shape {
        public void draw() {
            System.out.println("*********");
        }
    }

com.dc.sszostek.programs

清单.MF

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: Prog
    Bundle-SymbolicName: com.dc.sszostek.programs
    Bundle-Version: 1.0.0
    Bundle-Activator: com.dc.sszostek.programs.Activator
    Export-Package: com.dc.sszostek.programs
    Import-Package: org.osgi.framework, com.dc.sszostek.interfaces

Activator.java

    package com.dc.sszostek.programs;

    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceReference;
    import com.dc.sszostek.interfaces.Shape;

    public class Activator implements BundleActivator {
        private MyThread thread;

        public void start(BundleContext ctx) throws Exception {
            ServiceReference ref = getServiceReference(ctx);
            thread = new MyThread((Shape)ctx.getService(ref));
            thread.start();
        }

        public void stop(BundleContext ctx) throws Exception {
            ServiceReference ref = getServiceReference(ctx);
            ctx.ungetService(ref);
            thread.stopThread();
        }

        private ServiceReference getServiceReference(BundleContext ctx) {
            ServiceReference ref = ctx.getServiceReference(Shape.class.getName());
            return ref;
        }

        public static class MyThread extends Thread {
            private volatile boolean active = true;
            private final Shape service;

            public MyThread(Shape service) {
                this.service = service;
            }

            public void run() {
                while (active) {
                    service.draw();
                    try {
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        System.out.println("Thread interrupted: " + e.getMessage());
                    }
                }
            }

            public void stopThread() {
                active = false;
            }
        }
    }

com.dc.sszostek.programs

清单.MF

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: FileReceiver
    Bundle-SymbolicName: com.dc.sszostek.xmpp
    Bundle-Version: 1.0.0
    Bundle-Activator: com.dc.sszostek.xmpp.Activator
    Bundle-ClassPath: ., lib/smack-3.2.1.jar, lib/smackx-3.2.1.jar
    Import-Package: org.osgi.framework, javax.net, javax.security.auth.callback, javax.net.ssl, javax.security.sasl,
        javax.naming.directory, javax.naming

Activator.java

    package com.dc.sszostek.xmpp;

    import org.jivesoftware.smack.*;
    import org.jivesoftware.smackx.filetransfer.*;
    import org.osgi.framework.Bundle;
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.BundleException;

    import java.io.File;
    import java.io.IOException;

    public class Activator implements BundleActivator {
        private Connection connection;

        public void start(BundleContext bundleContext) throws Exception {
            final BundleContext ctx = bundleContext;

            try {
                connection = new XMPPConnection("JABBER_SERVER");
                connection.connect();
                connection.login("USER", "PASS");

                final FileTransferManager manager = new FileTransferManager(connection);
                FileTransferNegotiator.getInstanceFor(connection);
                FileTransferNegotiator.setServiceEnabled(connection, true);

                manager.addFileTransferListener(new FileTransferListener() {
                    public void fileTransferRequest(FileTransferRequest request) {
                        IncomingFileTransfer transfer = request.accept();

                        File file = new File("D:\\bundles\\" + transfer.getFileName());

                        try {
                            file.createNewFile();
                        } catch (IOException e) {
                            System.out.println(e.getMessage());
                        }

                        try {
                            transfer.recieveFile(file);
                        } catch (XMPPException e) {
                            System.out.println(e.getMessage());
                        }

                        Bundle bundle = ctx.getBundle(2); //com.dc.sszostek.implementations is bundle number 2
                        try {
                            bundle.update();
                        } catch (BundleException e) {
                            System.out.println(e.getMessage());
                        }
                    }
                });
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }

        public void stop(BundleContext bundleContext) throws Exception {
            connection.disconnect();
        }
    }

【问题讨论】:

    标签: java service osgi bundle


    【解决方案1】:

    不要从 OSGi 中的激活器开始,激活器是过去的不幸遗留物。激活器是单例(这真的很糟糕!),它们迫使您自己处理依赖关系。尽管它们有时在非常特殊的情况下很有用,因为它们不依赖于其他捆绑包。但是,几乎所有情况下,声明式服务都是可行的。

    很多人都想从底层学习 OSGi,但使用激活器就像学习如何驾驶 Fred Flintstone 的车在当今的道路上行驶。一定会让自己受伤。

    您实际上展示了使用激活器时发生在您身上的所有陷阱。当您启动激活器时,服务不保证存在。您还提出了一个非常糟糕的主意,即在您的激活器中打开与外部服务的连接。激活器启动/停止方法必须非常快速才能快速启动所有捆绑包。

    无论如何,除了尼尔的建议。您意识到 update() 正在使用您提供的旧网址吗?您是否更改了 URL 指向的文件?您可能想使用 update(InputStream) 方法来确保包确实更新了。

    【讨论】:

    • 感谢您的回答。我用过update(InputStream),它是解决方案的一部分。就像 Neil Bartlett 建议的那样,我也修改了线程。也谢谢你的cmets。这对我来说是一个练习,下一步将是提高解决方案的质量。我自己有一本“OSGi in action”,希望能有所帮助(如果您能推荐其他值得一读的书,我也将不胜感激?)。
    • 你应该读的当然是我的书 :-) 不幸的是它没有写出来,因为很难证明它是正确的:-(
    【解决方案2】:

    您是否希望在MyThread 运行时更改服务的实现?因为看起来您在启动线程之前只获得一次服务,然后永远重用它。在这些情况下,实现是不可能改变的,至少在你杀死并重新启动线程之前是这样。

    【讨论】:

    • 感谢您的回答。我已经更改了我的解决方案,将BundleContext 传递给线程并在其中获取ServiceReference,最后在每次使用它之前获得我的服务(这当然有时会在我的服务更新时导致异常,所以 ServiceReference 是然后为空)。正如 Peter Kriens 建议的那样,我也切换到了 update(InputStream),整个解决方案都奏效了。 (也很抱歉没有将您的答案也标记为已接受的答案,该网站不会让我将 2 个答案标记为已接受)。剩下的就是改进解决方案并了解更多信息。
    • 接受彼得的回答没问题。他在声望点上落后了,所以需要一点帮助;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-14
    • 2022-06-28
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多