来自另一个bundle的bundle.update()失败

时间:2013-02-25 13:23:28

标签: java service osgi bundle

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

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

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

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

    有人能告诉我我犯的错误在哪里,或者指出一个有效的例子吗?

    提前谢谢。


    com.dc.sszostek.interfaces

    MANIFEST.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

    MANIFEST.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

    MANIFEST.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

    MANIFEST.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();
            }
        }
    

2 个答案:

答案 0 :(得分:1)

不要从OSGi中的激活器开始,激活器是过去不幸的遗骸。激活者是单身人士(这真的很糟糕!)他们强迫你自己处理你的依赖。虽然它们在非常特殊的情况下有时很有用,因为它们不依赖于其他捆绑包。但是,几乎所有的声明式服务都是可行的。

许多人想从底层学习OSGi,但使用激活器就像学习如何驾驶弗雷德弗林特斯通汽车的今天的道路。一定会让自己受伤。

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

无论如何,除了尼尔的建议。你知道update()正在使用你给它的旧网址吗?您是否更改了URL指向的文件?您可能希望使用update(InputStream)方法来确保捆绑包真正更新。

答案 1 :(得分:0)

您希望在MyThread运行时更改服务的实施吗?因为看起来你只需要在启动线程之前获取一次服务,并永远重用它。在这些条件下,实现不可能改变,至少在你杀死并重新启动线程之前。