2013-02-25 36 views
0

我正在構建一個簡單的OSGi演示應用程序以瞭解該框架。我想更新另一個包中的活動包,或者從嵌入OSGi框架的應用程序更新活動包(如How To Embed OSGi by Neil Bartlett中所述)。來自另一個捆綁包的bundle.update()失敗

我的應用程序被分成這些軟件包(我已經放置代碼在帖子的末尾,方便閱讀):

  1. com.dc.sszostek.interfaces - 包含與單個形狀接口方法draw()
  2. com.dc.sszostek.implementations - 這個SymbolicName有兩個bundle,每個實現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包。

我的問題是,當我發送不同的實現到我的應用程序,文件被寫入,但捆綁不會得到更新。

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

清單。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(); 
     } 
    } 

回答

1

不要從OSGi中的激活劑開始,激活劑是過去不幸的遺體。激活者是單身人士(這真的很糟糕!),他們迫使你自己處理你的依賴關係。雖然它們在非常特殊的情況下有時是有用的,因爲它們不依賴於其他包。但是,幾乎所有的聲明式服務都是可行的。

許多人想從底層學習OSGi,但使用激勵器就像學習如何在弗雷德弗林斯通的車上駕駛今日的道路。必須受到傷害。

你實際上展示了當你使用激活器時發生在你身上的所有陷阱。當您啓動激活器時,服務不保證存在。你還會表現出一個非常糟糕的想法,在激活器中打開與外部服務的連接。激活器啓動/停止方法必須非常快速地啓動所有捆綁包。

無論如何,除了尼爾的建議。你意識到update()正在使用你給它的舊url?你是否改變了URL指向的文件?您可能想要使用update(InputStream)方法來確保該包實際上已更新。

+0

謝謝你的回答。我已經使用'update(InputStream)',它是解決方案的一部分。像Neil Bartlett建議的那樣,我也修改了這個線程。 也感謝您的意見。這對我來說是一個鍛鍊,下一步將會提高解決方案的質量。我有自己的「OSGi在行動」的副本,這將有助於(如果你可以推薦其他值得閱讀的書籍,我也會感到愧疚)。 – 2013-02-27 14:16:19

+0

你應該閱讀的當然是我的書:-)不幸的是,它不是書面的,因爲它很難證明它的寫法:-( – 2013-03-01 07:30:31

0

你所期望的服務的實現改變,而MyThread運行?因爲看起來你只有在啓動線程之前只獲得一次服務,並且永久重用它。在這些條件下,實現不可能改變,至少在你終止並重啓線程之前。

+0

謝謝你的回答。我已經改變了我的解決方案,將BundleContext傳遞給線程,並在每次使用前都獲取ServiceReference和服務(當然,當我的服務更新時,這有時會導致異常,所以ServiceReference是然後爲空)。我也轉向更新(InputStream),正如Peter Kriens所建議的那樣,整個解決方案都有效。 (也道歉沒有標記你的答案也作爲接受的答案,該網站不會讓我標記2答案被接受)。剩下的就是改進解決方案並學習更多東西。 – 2013-02-27 14:27:05

+0

接受彼得的答案沒有問題。他是名聲落後,所以需要一點點的支持;-) – 2013-02-27 18:04:45

相關問題