Chasing an mobile web vision

          闖蕩在移動(dòng)互聯(lián)網(wǎng)的世界中

          OSGi介紹(五)兩個(gè)bundle

          (四)中提到的直接型改造法實(shí)際上和一個(gè)傳統(tǒng)的java應(yīng)用程序沒(méi)有區(qū)別。因此客戶(hù)的需求發(fā)生變化,通常是牽一發(fā)而動(dòng)全身。
          那么我們現(xiàn)在就看看如果在osgi framework中,用多個(gè)bundle來(lái)實(shí)現(xiàn)的效果吧。
          我的想法是用兩個(gè)bundle來(lái)配合實(shí)現(xiàn)“扶貧助手”的功能。一個(gè)bundle專(zhuān)門(mén)負(fù)責(zé)錄入和顯示紀(jì)錄,一個(gè)bundle專(zhuān)門(mén)負(fù)責(zé)紀(jì)錄的數(shù)據(jù)結(jié)構(gòu)和對(duì)數(shù)據(jù)的處理,用時(shí)下時(shí)髦的說(shuō)法就是使用了mvc,只是我的m和c放到了一起。
          先看看mc的bundle實(shí)現(xiàn)代碼片斷:

          package com.wukong.test.family.control;
          import java.util.*;
          import com.wukong.test.family.control.impl.*;
          public interface FamilyInfoDatabase {
              
          public static class FamilyFactory {
                  
          private static FamilyInfoDatabase database;
                  
          public static FamilyInfoDatabase getDatabaseInstance(){
                      
          if(database == null){
                          database 
          = new FamilyDatabase();
                      }

                      
          return database;
                  }

              }

              
          public String[] getColumns();
              
          public Object getValueAt(int row, int column);
              
          public String[] getSortingFields();
              
          public int getRowCount();
              
              
          public void sort(String sortField) throws IllegalArgumentException;
              
              
          public void addEntry(List columns, List values) throws IllegalArgumentException;
              
          public void deleteEntry(String familyName);
              
          public void update(String familyName,List columns, List values)throws IllegalArgumentException;
          }



          這個(gè)interface是用來(lái)描述一個(gè)數(shù)據(jù)庫(kù)所具備的基本功能。注意,這個(gè)interface被放到了package com.wukong.test.family.control中。
          另外,這個(gè)interface還提供了一個(gè)內(nèi)嵌類(lèi),用來(lái)專(zhuān)門(mén)提供一個(gè)工廠方法來(lái)產(chǎn)生唯一的一個(gè)數(shù)據(jù)庫(kù)實(shí)例。
          對(duì)于這個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn),代碼片斷如下(增加,刪除和修改的代碼都被省略了,只給出排序的代碼):
          package com.wukong.test.family.model.impl;
          public class FamilyInfoEntry {
              
          private String familyName;
              
          private int population;
              
          private int incomePerYear;
              
              FamilyInfoEntry(String familyName,
          int population,int income){
                  
          this.familyName = familyName;
                  
          this.population = population;
                  
          this.incomePerYear = income;
              }

              
              
              String getFamilyName() 
          {
                  
          return familyName;
              }

              
          int getIncomePerYear() {
                  
          return incomePerYear;
              }

              
          int getPopulation() {
                  
          return population;
              }

          }


          package com.wukong.test.family.control.impl;
          import com.wukong.test.family.control.FamilyInfoDatabase;
          import java.util.*;
          public class FamilyDatabase implements FamilyInfoDatabase {
              
          private LinkedList familyEntryList = new LinkedList();
              
          private Object[] sortedValues = null;
              
          public FamilyDatabase() {
                  
          this.familyEntryList.add(new FamilyInfoEntry("Zhang",3,1200));
                  
          this.familyEntryList.add(new FamilyInfoEntry("Li",6,1800));
                  
          this.familyEntryList.add(new FamilyInfoEntry("Liu",4,1500));
                  
          this.sortedValues = this.familyEntryList.toArray();
              }

              
          public String[] getColumns() {
                  
          return new String[] "Family Name""Family Population""Income" };
              }

              
          public Object getValueAt(int row, int column) {
                  FamilyInfoEntry entry 
          = (FamilyInfoEntry)this.sortedValues[row];
                  
          switch (column) {
                  
          case 0:
                      
          return entry.getFamilyName();
                  
          case 1:
                      
          return new Integer(entry.getPopulation());
                  
          case 2:
                      
          return new Integer(entry.getIncomePerYear());
                  
          default:
                      
          throw new IllegalArgumentException("Invalid column index.");
                  }

              }

              
          public String[] getSortingFields() {
                  
          return new String[] "FamilyName","Income" };
              }

              
          public int getRowCount() {
                  
          return this.familyEntryList.size();
              }

              
          public void addEntry(List columns, List values)
                      
          throws IllegalArgumentException {
              }

              
          public void deleteEntry(String familyName) {
              }

              
          public void update(String familyName, List columns, List values)
                      
          throws IllegalArgumentException {
              }


              
          public void sort(String sortField) throws IllegalArgumentException{
                  
          if(sortField.equals("FamilyName")){
                      
          this.sortedValues = this.familyEntryList.toArray();
                      Arrays.sort(
          this.sortedValues,new SortedByName());
                      
                  }

                  
          if(sortField.equals("Income")){
                      
          this.sortedValues = this.familyEntryList.toArray();
                      Arrays.sort(
          this.sortedValues,new SortedByIncome());
                  }

           
          throw new IllegalArgumentException("Sorting enties by field '" + sortField + "' is not supported."); 
              }

              
              
          class SortedByName implements Comparator{
                  
          public int compare(Object entry1,Object entry2) {
                      
          if (entry1 == entry2) {
                          
          return 0;
                      }

                      FamilyInfoEntry en1 
          = (FamilyInfoEntry) entry1;
                      FamilyInfoEntry en2 
          = (FamilyInfoEntry) entry2;
                      
                      
          return en1.getFamilyName().compareTo(en2.getFamilyName());
                  }

                  
              }

              
              
          class SortedByIncome implements Comparator {
                  
          public int compare(Object entry1, Object entry2) {
                      
          if (entry1 == entry2) {
                          
          return 0;
                      }

                      FamilyInfoEntry en1 
          = (FamilyInfoEntry) entry1;
                      FamilyInfoEntry en2 
          = (FamilyInfoEntry) entry2;
                      
          return en1.getIncomePerYear() - en2.getIncomePerYear();
                  }

              }

          }



          同樣需要注意的是我們把這個(gè)實(shí)現(xiàn)放到了package com.wukong.test.family.control.impl中
           
          下面看看v的bundle實(shí)現(xiàn)。

          package com.wukong.test.family.gui;
          import org.osgi.framework.*;
          import javax.swing.*;
          import javax.swing.table.*;
          import java.awt.*;
          import java.awt.event.*;
          import com.wukong.test.family.control.*;
          public class FamilyInfoGui implements BundleActivator, ActionListener,ItemListener {
              
          private JFrame mainFrame;
              
          private JPanel contentPanel;
              
          private JTable familiesTable;
              
          private JScrollPane familiesTableScrollPane;
              
          private JPanel sortedByPanel = new JPanel(new GridLayout(12));
              
          private JLabel sortedByLabel = new JLabel("Sorted By: ");
              
          private JComboBox sortedByList = null;
              
          private JPanel commandPanel = new JPanel(new GridLayout(13));
              
          private JButton addEntry = new JButton("Add");
              
          private JButton deleteEntry = new JButton("Delete");
              
          private JButton updateEntry = new JButton("Update");
              
              FamilyInfoDatabase database 
          = null;
              
          public void start(BundleContext context) throws Exception {
                  Runnable r 
          = new Runnable() {
                      
          public void run() {
                          contentPanel 
          = new JPanel();
                          familiesTableScrollPane 
          = new JScrollPane();
                          database 
          = FamilyInfoDatabase.FamilyFactory
                                  .getDatabaseInstance();
                          familiesTable 
          = new JTable(new FamilyInfoTableModel(database));
                          familiesTableScrollPane.setViewportView(familiesTable);
                          
                          String[] sortedFields 
          = database.getSortingFields();
                          
                          sortedByList 
          = new JComboBox(sortedFields);
                          
                          sortedByList.addItemListener(FamilyInfoGui.
          this);
                          sortedByPanel.add(sortedByLabel);
                          sortedByPanel.add(sortedByList);
                          commandPanel.add(addEntry);
                          commandPanel.add(deleteEntry);
                          commandPanel.add(updateEntry);
                          contentPanel.add(sortedByPanel, BorderLayout.NORTH);
                          contentPanel.add(familiesTableScrollPane, BorderLayout.CENTER);
                          contentPanel.add(commandPanel, BorderLayout.SOUTH);
                          mainFrame 
          = new JFrame();
                          mainFrame.setContentPane(contentPanel);
                          mainFrame.setSize(
          new Dimension(500600));
                          mainFrame.show();
                      }

                  }
          ;
                  Thread t 
          = new Thread(r);
                  t.start();
              }

              
          public void stop(BundleContext context) throws Exception {
                  
          this.mainFrame.dispose();
              }

              
          public void actionPerformed(ActionEvent event) {
              }

              
              
              
          public void itemStateChanged(ItemEvent event) {
                  
          if(event.getSource() == this.sortedByList){
                      String sortingField 
          = (String)event.getItem();
                      
          this.database.sort(sortingField);
                      
          this.familiesTable.repaint();
                  }

              }

              
          class FamilyInfoTableModel extends AbstractTableModel {
                  
          private FamilyInfoDatabase database;
                  FamilyInfoTableModel(FamilyInfoDatabase database) 
          {
                      
          this.database = database;
                  }

                  
          public String getColumnName(int col) {
                      
          return database.getColumns()[col];
                  }

                  
          public boolean isCellEditable(int row, int col) {
                      
          return false;
                  }

                  
          public int getColumnCount() {
                      
          return database.getColumns().length;
                  }

                  
          public int getRowCount() {
                      
          return database.getRowCount();
                  }

                  
          public Object getValueAt(int row, int col) {
                      
          return database.getValueAt(row, col);
                  }

              }

          }


          v的實(shí)現(xiàn)基本是界面的構(gòu)造,而關(guān)于數(shù)據(jù)庫(kù),它只能看到interface FamilyInfoDatabase,因?yàn)樗籭mport com.wukong.test.family.control.*,然后通過(guò)FamilyInfoDatabase內(nèi)嵌靜態(tài)類(lèi)的靜態(tài)工廠方法獲得數(shù)據(jù)庫(kù)的實(shí)例,這樣它完全不用關(guān)心數(shù)據(jù)庫(kù)如何實(shí)現(xiàn)。
           
          源碼編譯后得到class文件后,下一步我們的工作就要來(lái)構(gòu)造這兩個(gè)bundle。最關(guān)鍵的步驟就是為每個(gè)bundle寫(xiě)它的manifest文件
          我們先給出mc bundle的manifest文件(familycontrol.mf):
          Manifest-Version: 1.0
          Bundle-SymbolicName: com.wukong.test.family.control
          Bundle-Name: family control
          Bundle-Version: 
          1.0
          Bundle-Vendor: LiMing
          Export-Package: com.wukong.test.family.control


          非常簡(jiǎn)單,但請(qǐng)大家注意這行
          Export-Package: com.wukong.test.family.control
          它告訴framework,這個(gè)bundle提供com.wukong.test.family.control這個(gè)包。
          所謂“bundle A提供某個(gè)包”意思,通俗簡(jiǎn)單的理解是如果bundle B在manifest文件中說(shuō)明要使用這個(gè)包(通過(guò)Import-Package這個(gè)關(guān)鍵字,下面會(huì)在v bundle中有說(shuō)明)那么bundle B運(yùn)行時(shí),當(dāng)使用到這個(gè)包中的類(lèi)時(shí),framework將告訴B的class loader這個(gè)類(lèi)的定義是來(lái)自bundle A,從而不會(huì)發(fā)生ClassNotFoundException。另外值得一提的是我們并沒(méi)有把com.wukong.test.family.control.impl這個(gè)包加進(jìn)來(lái),這樣做的目的也是為了隱藏具體實(shí)現(xiàn)。將來(lái)只要interface不變,我們可以使用不同的實(shí)現(xiàn)來(lái)替換現(xiàn)有實(shí)現(xiàn),大大提高擴(kuò)展性。
           
          還有一點(diǎn),細(xì)心的話,你會(huì)發(fā)現(xiàn)這個(gè)bundle沒(méi)有activator。這是允許的,這種bundle就像動(dòng)態(tài)連接庫(kù),只提供接口和方法以及實(shí)現(xiàn),等待其他實(shí)體的調(diào)用,而本身不能運(yùn)行。
          再來(lái)看看v bundle的manifest文件(family.mf):

          Manifest-Version: 1.0
          Bundle-SymbolicName: com.wukong.test.family.gui
          Bundle-Name: family gui
          Bundle-Version: 
          1.0
          Bundle-Vendor: LiMing
          Bundle-Activator: com.wukong.test.family.gui.FamilyInfoGui
          Import-Package: org.osgi.framework
          ;version=1.3,com.wukong.test.family.control


          正如上面曾經(jīng)提到過(guò)的一樣,我們?cè)贗mport-Package:關(guān)鍵字中指定該bundle需要使用com.wukong.test.family.control包。在v bundle的源代碼中,我們也看到這個(gè)bundle的確使用了com.wukong.test.family.control包中的FamilyInfoDatabase。更深入一點(diǎn),我們可以簡(jiǎn)單的這樣理解,當(dāng)v bundle運(yùn)行的時(shí)候,framework通過(guò)匹配bundle間的Import-Package和Export-Package,
          然后告訴v bundle,F(xiàn)amilyInfoDatabase這個(gè)類(lèi)型的定義和裝載實(shí)際上是由mc bundle完成的。這樣,v bundle就會(huì)使用mc bundle的class loader來(lái)加在這個(gè)類(lèi)型。另外,按照osgi framework的spec規(guī)定,javax.swing;javax.swing.table;java.awt;java.awt.event這4個(gè)包都都不屬于framework的必備包,所以應(yīng)該在Import-Package中指定。為了不用在Import-Package中指定這4個(gè)包,這個(gè)例子要求運(yùn)行在sun的j2se的jvm(比如version 1.4.2_04),這樣4個(gè)包都作為java api由bootstrap classloader加載,每個(gè)bundle都可以直接使用了。
           
          有了manifest文件,我們最后就是打jar包了。
          比如在windows下,你把兩個(gè)manifest文件放在包的根目錄,然后執(zhí)行以下命令
          jar -cvfm family.jar family.mf com\wukong\test\family\gui\*.class
          jar -cvfm familycontrol.jar familycontrol.mf com\wukong\test\family\control
          這樣,我們就可以認(rèn)為family.jar是我們的v bundle而familycontrol.jar是我們的mc bundle。
          下面,我們就來(lái)安裝運(yùn)行這兩個(gè)bundle吧。
          我將首先簡(jiǎn)單介紹一個(gè)我自己編寫(xiě)的osgi framework,然后結(jié)合這個(gè)demo framework來(lái)部署和運(yùn)行新的“扶貧助手”。
          本人編寫(xiě)的osgi framework基本上完成了spec r4的核心規(guī)范,但是與安全相關(guān)的功能都沒(méi)有實(shí)現(xiàn)。
          啟動(dòng)這個(gè)framework后,它的shell提供了如下簡(jiǎn)單的framework管理功能命令:
          bl 即bundle list,查看所有已經(jīng)安裝的bundle
          dl 即detailed bundle list,用來(lái)查看某個(gè)bundle的詳細(xì)信息
          sl 即service list,用來(lái)查看所有已經(jīng)注冊(cè)的service
          ls 即list setting,用來(lái)查看所有設(shè)置的系統(tǒng)屬性(System.getProperties)和framework當(dāng)前的active start level
          in 即install bundle,通過(guò)指定bundle文件的url來(lái)安裝該bundle
          up 即update bundle,通過(guò)指定bundle id來(lái)升級(jí)指定的bundle
          un 即uninstall bundle,通過(guò)指定bundle id來(lái)卸載指定的bundle
          stt 即start bundle,通過(guò)指定bundle id來(lái)啟動(dòng)指定的bundle
          stp 即stop bundle,通過(guò)指定bundle id來(lái)停止指定bundle的運(yùn)行
          rst 即restart bundle,通過(guò)指定bundle id來(lái)重新啟動(dòng)指定的bundle
          rfr 即refresh package,當(dāng)某些bundle被更新或卸載后,如果不執(zhí)行這個(gè)命令,那么被更新或卸載的bundle的Export-Package(如果有的話)將繼續(xù)服役,
          也就是說(shuō),之前使用這些包的bundle不會(huì)因?yàn)檫@個(gè)bundle被更新或者卸載而發(fā)生變化。而執(zhí)行這個(gè)命令后,受影響的bundle將被重新解析
          rest 即restart,重新啟動(dòng)framework,屬于“熱起”
          shut 即shutdown,停止整個(gè)framework的運(yùn)行
          set 用來(lái)設(shè)置framework的active startlevel或者某個(gè)bundle的start level
          log 用來(lái)查看系統(tǒng)的日志信息
          現(xiàn)在我們來(lái)假設(shè)運(yùn)行環(huán)境如下:
          OS: window
          jvm: j2se 1.4.2_04
          family.jar和familycontrol.jar這兩個(gè)文件放在D:/framework/bundles目錄下
          第一步:安裝bundle
          輸入以下兩條命令:
          in file:D:/framework/bundles/familycontrol.jar
          in file:D:/framework/bundles/family.jar
          然后用bl命令查看結(jié)果,其中得到如下顯示結(jié)果:
          Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name
          0  OSGiFramework Active  0  System Bundle     system.bundle
          .
          .(省略部分結(jié)果顯示)
          .
          16  family control Installed 1  file:D:/framework/bundles/familycontrol.jar com.wukong.test.family.control
          17  family gui Installed 1  file:D:/framework/bundles/family.jar  com.wukong.test.family.gui
          說(shuō)明兩個(gè)bundle安裝成功,其中mc bundle的id是16, v bundle的id是17
          第二步:?jiǎn)?dòng)bundle
          可以輸入以下命令
          stt 16,17
          然后我們就可以看到一個(gè)JFrame顯示出來(lái),里面顯示了3條記錄,沒(méi)有任何順序(其順序?qū)嶋H上是在程序中添加到LinkedList的順序)。我們可以在Sorted By的列表中看到有兩個(gè)選擇“FamilyName”和“Income”,當(dāng)選擇“Income”時(shí),你將發(fā)現(xiàn)3條記錄按年收入由小到大排列起來(lái)。程序的運(yùn)行完全符合我們的意圖。
          這時(shí)如果我們?cè)儆胋l命令查看,將得到如下結(jié)果:
          Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name
          0  OSGiFramework Active  0  System Bundle     system.bundle
          .
          .(省略部分結(jié)果顯示)
          .
          16  family control Resolved 1  file:D:/framework/bundles/familycontrol.jar com.wukong.test.family.control
          17  family gui Active  1  file:D:/framework/bundles/family.jar  com.wukong.test.family.gui
          注意:由于mc bundle沒(méi)有Activator,所以啟動(dòng)這個(gè)bundle只會(huì)使其進(jìn)入Resolved狀態(tài)。

          有了這樣的結(jié)構(gòu),程序變得靈活些了。現(xiàn)在假設(shè)客戶(hù)提出需要增加一個(gè)字段,即人均年收入,并且提供按人均年收入排列紀(jì)錄。看看framework框架下,這樣的變動(dòng)是如何的簡(jiǎn)單!
          首先,我們通過(guò)分析,發(fā)現(xiàn)只要更改mc bundle的代碼,使得數(shù)據(jù)庫(kù)的實(shí)現(xiàn)中增加這個(gè)字段以及相應(yīng)的排序方法即可。更新后的代碼如下:

          package com.wukong.test.family.control.impl;
          import com.wukong.test.family.control.FamilyInfoDatabase;
          import java.util.*;
          public class FamilyDatabase implements FamilyInfoDatabase {
              
          private LinkedList familyEntryList = new LinkedList();
              
          private Object[] sortedValues = null;
              
          public FamilyDatabase() {
                  
          this.familyEntryList.add(new FamilyInfoEntry("Zhang",3,1260));
                  
          this.familyEntryList.add(new FamilyInfoEntry("Li",6,1800));
                  
          this.familyEntryList.add(new FamilyInfoEntry("Liu",4,1500));
                  
          this.sortedValues = this.familyEntryList.toArray();
              }

              
          public String[] getColumns() {
                  
          return new String[] "Family Name""Family Population""Income" ,"IncomePerPerson"};//添加了“IncomePerPerson”字段
              }

              
          public Object getValueAt(int row, int column) {
                  FamilyInfoEntry entry 
          = (FamilyInfoEntry)this.sortedValues[row];
                  
          switch (column) {
                  
          case 0:
                      
          return entry.getFamilyName();
                  
          case 1:
                      
          return new Integer(entry.getPopulation());
                  
          case 2:
                      
          return new Integer(entry.getIncomePerYear());
                  
          case 3:
                      
          return new Integer(entry.getIncomePerYear()/entry.getPopulation());//計(jì)算人均年收入
                  default:
                      
          throw new IllegalArgumentException("Invalid column index.");
                  }

              }

              
          public String[] getSortingFields() {
              }

              
          public int getRowCount() {
                  
          return this.familyEntryList.size();
              }

              
          public void addEntry(List columns, List values)
                      
          throws IllegalArgumentException {
                  
          // TODO Auto-generated method stub
              }

              
          public void deleteEntry(String familyName) {
                  
          // TODO Auto-generated method stub
              }

              
          public void update(String familyName, List columns, List values)
                      
          throws IllegalArgumentException {
                  
          // TODO Auto-generated method stub
              }

              
          public void sort(String sortField) throws IllegalArgumentException{
                  
          if(sortField.equals("FamilyName")){
                      
          this.sortedValues = this.familyEntryList.toArray();
                      Arrays.sort(
          this.sortedValues,new SortedByName());
                      
                  }

                  
          if(sortField.equals("Income")){
                      
          this.sortedValues = this.familyEntryList.toArray();
                      Arrays.sort(
          this.sortedValues,new SortedByIncome());
                  }

                  
          if(sortField.equals("IncomePerPerson")){//對(duì)紀(jì)錄按人均年收入進(jìn)行排序
                      this.sortedValues = this.familyEntryList.toArray();
                      Arrays.sort(
          this.sortedValues,new SortedByIPP());
                      
                  }

              }

              
              
          class SortedByName implements Comparator{
                  
          public int compare(Object entry1,Object entry2) {
                      
          if (entry1 == entry2) {
                          
          return 0;
                      }

                      FamilyInfoEntry en1 
          = (FamilyInfoEntry) entry1;
                      FamilyInfoEntry en2 
          = (FamilyInfoEntry) entry2;
                      
                      
          return en1.getFamilyName().compareTo(en2.getFamilyName());
                  }

                  
              }

              
              
          class SortedByIncome implements Comparator {
                  
          public int compare(Object entry1, Object entry2) {
                      
          if (entry1 == entry2) {
                          
          return 0;
                      }

                      FamilyInfoEntry en1 
          = (FamilyInfoEntry) entry1;
                      FamilyInfoEntry en2 
          = (FamilyInfoEntry) entry2;
                      
          return en1.getIncomePerYear() - en2.getIncomePerYear();
                  }

              }

              
              
          class SortedByIPP implements Comparator {//人均年收入的排序標(biāo)準(zhǔn)。
                  public int compare(Object entry1, Object entry2) {
                      
          if (entry1 == entry2) {
                          
          return 0;
                      }

                      FamilyInfoEntry en1 
          = (FamilyInfoEntry) entry1;
                      FamilyInfoEntry en2 
          = (FamilyInfoEntry) entry2;
                      
          return (en1.getIncomePerYear()/en1.getPopulation()) - (en2.getIncomePerYear()/en2.getPopulation());
                  }

                  
              }

          }




          編譯完畢后,我們把mc bundle的manifest文件改為如下:

          Manifest-Version: 1.0
          Bundle-SymbolicName: com.wukong.test.family.control
          Bundle-Name: family control
          Bundle-Version: 
          2.0 //由1.0改為2.0
          Bundle-Vendor: LiMing
          Export-Package: com.wukong.test.family.control


          然后使用jar工具打包,并把產(chǎn)生的新的familycontrol.jar依舊放在D:/framework/bundles目錄下。
          這時(shí),我們只要執(zhí)行下面的命令,framework就完成對(duì)mc bundle的升級(jí)工作:
          up 16
          升級(jí)完畢后,你會(huì)發(fā)現(xiàn)v bundle的顯示依舊沒(méi)有任何變化。這時(shí)我們需要執(zhí)行一個(gè)refresh package命令,來(lái)更新bundle的解析:
          rfr
          這時(shí),你會(huì)發(fā)現(xiàn)原來(lái)的JFrame被關(guān)閉了,然后又一個(gè)JFrame顯示出來(lái),里面的紀(jì)錄多了一列“IncomePerPerson”,而且在“Sorted By”里面也
          多了“IncomePerPerson”,而且,排序的結(jié)果也很正確。
          瞧,framework為應(yīng)用程序提供了強(qiáng)大的動(dòng)態(tài)更新功能,非常方便。甚至都不用重新啟動(dòng)framework,更不用說(shuō)JVM了。您也許會(huì)說(shuō),最終用戶(hù)根本不可能幫你輸入這些什么in,up晦澀的命令。還有,讓用戶(hù)拷貝新版本到本地似乎也不是什么好主意。嗯,這個(gè)問(wèn)題說(shuō)得很對(duì)。其實(shí)我是偷懶了,這些操作framework都留有接口,我們只要再編寫(xiě)一個(gè)專(zhuān)門(mén)管理這兩個(gè)bundle升級(jí)的第三個(gè)bundle就可以了,這個(gè)bundle將提供友好的界面來(lái)告訴最終用戶(hù)如何升級(jí)。這樣就能夠提供比較好的解決方案了。至于第二個(gè)問(wèn)題,別忘了bundle的location是一個(gè)url,只要jvm注冊(cè)了相應(yīng)的url handler完全可以支持http,ftp等豐富的url,例如,升級(jí)的時(shí)候,framework自動(dòng)連接到供應(yīng)商的http下載服務(wù)器獲取最新版本進(jìn)行更新,當(dāng)然,我們也可以把更強(qiáng)大更靈活的升級(jí)功能及選項(xiàng)加入到上面提到的第三個(gè)bundle中,從而極大提高了程序的易用性,而且極大降低了軟件提供商的維護(hù)成本。
           
          到此為止,我已經(jīng)想不出再多好話了,但是,還可以更好!下一節(jié),將采用service的方式來(lái)實(shí)現(xiàn),嘿嘿,情況又會(huì)不一樣了,到時(shí)候我會(huì)對(duì)比一下這兩種實(shí)現(xiàn)方式的優(yōu)劣。
           
          題外話:抱歉沒(méi)有拿某個(gè)著名的產(chǎn)品或者open source的產(chǎn)品來(lái)舉例,我打算把自己的實(shí)現(xiàn)也opensource,有興趣參與嗎?不管怎樣,過(guò)兩天就把實(shí)現(xiàn)上傳上來(lái),歡迎拍磚。

          posted on 2006-02-14 16:02 勤勞的蜜蜂 閱讀(4392) 評(píng)論(3)  編輯  收藏

          評(píng)論

          # re: OSGi介紹(五)兩個(gè)bundle 2007-06-22 10:27 hata

          這章講的比較長(zhǎng),要耐心看,有點(diǎn)遺憾的是沒(méi)有把工具放上來(lái)我測(cè)試不鳥(niǎo)。在eclipse里的equinox插件里只能看到bundle啟動(dòng)與否的提示,看不到運(yùn)行結(jié)果,很是郁悶。希望快點(diǎn)把實(shí)現(xiàn)傳上來(lái)啊!
          我分析下我的看法,看對(duì)不對(duì)啊:
          我有2個(gè)bundle:bundleA & bundleB
          bundleA里我寫(xiě)入: interface,pojo,iterfaceImpl
          (在manifese里:Export-Package對(duì)外提供接口)
          bundleB里我寫(xiě)入: 一系列的業(yè)務(wù)方法.
          (在manifese里:Import-Package獲取bundleA的服務(wù))
          那么這個(gè)時(shí)候就能運(yùn)用到OSGI的功能了?我即時(shí)更新bundleA的話那么bundleB會(huì)相應(yīng)發(fā)生變化!這就完成了最基本的OSGI的功能?
          ===>
          附錄:針對(duì)OSGI實(shí)戰(zhàn)上的例子,那么功能基本相同,只是擴(kuò)展了bundleB,多寫(xiě)了2個(gè)bundleC,bundleD?只是里面用到了servlet和service,我想我要看看你下面寫(xiě)的才知道怎么應(yīng)用到上面.估計(jì)理解完后調(diào)通例子也就能進(jìn)一步了解了.
          ===>
          我們做J2EE,只是想把接口放在OSGI里,經(jīng)理也只是這么說(shuō),希望能用這個(gè)做吧....期待你更多的OSGI的資料,我想你這個(gè)blog也算國(guó)內(nèi)討論osgi少有的好地方,加油加油!  回復(fù)  更多評(píng)論   

          # re: OSGi介紹(五)兩個(gè)bundle[未登錄](méi) 2009-07-24 10:04 han

          有點(diǎn)長(zhǎng)。。現(xiàn)在也不干活了。。天天看OSGI。。呵呵  回復(fù)  更多評(píng)論   

          # re: OSGi介紹(五)兩個(gè)bundle[未登錄](méi) 2009-07-24 17:26 han

          我想問(wèn)一下:FamilyInfoEntry 這個(gè)類(lèi)不放到mc bundle的manifest文件中嗎?
          這個(gè)要怎么處理?  回復(fù)  更多評(píng)論   


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 东至县| 元谋县| 辽阳市| 手机| 崇礼县| 册亨县| 古蔺县| 泽库县| 甘德县| 门头沟区| 龙川县| 恩平市| 松阳县| 宝应县| 永昌县| 万宁市| 新沂市| 台东市| 宁乡县| 阜平县| 平南县| 平罗县| 泰宁县| 英德市| 阿克陶县| 红安县| 中江县| 甘洛县| 桃园县| 沁源县| 古田县| 阜南县| 宜黄县| 嘉善县| 佳木斯市| 通辽市| 香港 | 浦北县| 图们市| 诸城市| 浮梁县|