Chasing an mobile web vision

          闖蕩在移動互聯網的世界中

          OSGi介紹(六)OSGi的service

          在給出采用service方式實現的“扶貧助手”之前,我們稍微回顧一下上一篇的成果。
          在(五)中,我們看到程序被分成多個bundle后,程序的模塊程度得到提高,而控制模塊間的耦合度由Import-Package和Export-Package來控制,相對比較靈活。另一方面程序的更新和升級的粒度變小了。誰都知道只更新部分要比全部更新強,尤其當更新發生在一些需要建立昂貴的連接時,細粒度會節省不少花銷。除了這些,我們看不到其他新鮮的東西。說白了,也就是挖空心思想一些design pattern來劃分程序模塊。
           
          好了,馬上就新鮮了。下面你會看到通過采用service方式來改造(五)中的程序,gui bundle在某些情況下不用重新啟動,就能直接某些適應需求的變更!
          先給出model bundle的代碼,該bundle包含兩個java package,分別是:
          com.bajie.test.family.model
          com.bajie.test.family.model.impl
          在com.bajie.test.family.model這個package中包含如下的class和interface:
          package com.bajie.test.family.model;
          import java.util.List;
          import javax.swing.table.AbstractTableModel;
          public abstract class FamilyInfoDatabase extends AbstractTableModel{
             
              public abstract void sort(SortingFamilyInfoCriteria sortField) throws IllegalArgumentException;
             
              public abstract void addEntry(List columns, List values) throws IllegalArgumentException;
              public abstract void deleteEntry(String familyName);
              public abstract void update(String familyName,List columns, List values)throws IllegalArgumentException;
          }

          這是database的model,與(五)定義成interface不同,我們直接讓它繼承了AbstractTableModel,這是因為我們希望當數據或顯示需求變化時,gui上的JTable能獲得通知,并顯示更新的結果。SortingFamilyInfoCriteria這個類型下文會給出說明。
           
          package com.bajie.test.family.model;
          public class FamilyInfoEntry {
              private String familyName;
              private int population;
              private int incomePerYear;
             
              public FamilyInfoEntry(String familyName,int population,int income){
                  this.familyName = familyName;
                  this.population = population;
                  this.incomePerYear = income;
              }
             
              public String getFamilyName() {
                  return familyName;
              }
              public int getIncomePerYear() {
                  return incomePerYear;
              }
              public int getPopulation() {
                  return population;
              }
          }

          這個類的結構和在(五)中完全一樣,用來紀錄一條家庭信息。唯一不同的是,在(五)中我們把它放入了實現(.impl)package中,在后面給出bundle的manifest文件時,我將解釋為什么要這樣改。
           
          package com.bajie.test.family.model;
          public interface FamilyInfoColumn {
              public Object getColumnValue(FamilyInfoEntry entry);
             
              public String getColumnName();
          }
          這個類用來描述table中的某個列。
          package com.bajie.test.family.model;
          import java.util.Comparator;
          public interface SortingFamilyInfoCriteria extends Comparator{
              public String getSortFieldString();
          }
          這個類將用于對家庭紀錄按某一列的值進行排序。
          在com.bajie.test.family.model.impl這個package中包含上面抽象類和interface的實現:
          package com.bajie.test.family.model.impl;
          import java.util.Arrays;
          import java.util.LinkedList;
          import java.util.List;
          import org.osgi.framework.BundleActivator;
          import org.osgi.framework.BundleContext;
          import org.osgi.framework.Constants;
          import org.osgi.framework.ServiceEvent;
          import org.osgi.framework.ServiceListener;
          import org.osgi.framework.ServiceReference;
          import com.bajie.test.family.model.FamilyInfoColumn;
          import com.bajie.test.family.model.FamilyInfoDatabase;
          import com.bajie.test.family.model.FamilyInfoEntry;
          import com.bajie.test.family.model.SortingFamilyInfoCriteria;
          public class FamilyDatabase extends FamilyInfoDatabase implements  BundleActivator,
                  ServiceListener {
              private LinkedList familyEntryList = new LinkedList();
              private Object[] sortedValues = null;
              private LinkedList columns = new LinkedList();
              private BundleContext context;
              public int getColumnCount() {
                  return this.columns.size();
              }
              public String getColumnName(int index) {
                  return ((FamilyInfoColumn)columns.get(index)).getColumnName();
              }
             
              public Object getValueAt(int row, int column) {
                  FamilyInfoEntry entry = (FamilyInfoEntry) this.sortedValues[row];
                  if(column >= this.familyEntryList.size()){
                      return null;
                  }
                  return ((FamilyInfoColumn) this.columns.get(column))
                          .getColumnValue(entry);
              }
              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(SortingFamilyInfoCriteria sortField) {
                  Arrays.sort(this.sortedValues, sortField);
              }
              public void start(BundleContext context) throws Exception {
                  this.context = context;
                  this.familyEntryList.add(new FamilyInfoEntry("Zhang", 3, 1200));
                  this.familyEntryList.add(new FamilyInfoEntry("Li", 6, 1800));
                  this.familyEntryList.add(new FamilyInfoEntry("Liu", 5, 1500));
                  this.familyEntryList.add(new FamilyInfoEntry("Wang", 4, 1300));
                 
                  this.sortedValues = this.familyEntryList.toArray();
           //向framework注冊一個類型為FamilyInfoDatabase的服務
                  context.registerService(FamilyInfoDatabase.class.getName(),this,null);
           //向framework注冊三個服務,每個服務的類型既為FamilyInfoColumn,也是SortingFamilyInfoCriteria
                  String[] clazzes = new String[] {FamilyInfoColumn.class.getName(),SortingFamilyInfoCriteria.class.getName()};
                  context.registerService(clazzes,new FamilyNameColumn(),null);
                  context.registerService(clazzes,new FamilyPopulationColumn(),null);
                  context.registerService(clazzes,new FamilyIncomeColumn(),null);
                 
           //向framework查找所有注冊類型為FamilyInfoColumn的服務
           //先獲得服務的引用
                  ServiceReference[] columnRefs = context.getServiceReferences(
                          FamilyInfoColumn.class.getName(), null);
                  FamilyInfoColumn column = null;
                  for (int i = 0; i < columnRefs.length; i++) {
                      System.out.println(i + ":" + ((String[])(columnRefs[i].getProperty(Constants.OBJECTCLASS)))[0]);
               //通過引用獲得具體的服務對象,每一個對象都將轉化成gui中table的一列
                      column = (FamilyInfoColumn) context.getService(columnRefs[i]);
                      if (column != null) {
                          this.columns.add(column);
                      }else{
                          System.out.println("null service object.");
                      }
                  }

           //注冊服務偵聽器,該偵聽器專門偵聽FamilyInfoColumn服務對象的動態(主要是增加和刪除)
                  context.addServiceListener(this,"(" + Constants.OBJECTCLASS + "="
                          + FamilyInfoColumn.class.getName() + ")");
              }
              public void stop(BundleContext context) throws Exception {
              }
              public void serviceChanged(ServiceEvent event) {
                  switch (event.getType()) {
                  case ServiceEvent.MODIFIED:
                      return;
                  case ServiceEvent.REGISTERED://表明有新的列產生了。
                      ServiceReference ref = event.getServiceReference();
                      Object service = this.context.getService(ref);
                      this.columns.add(service);
                      this.fireTableStructureChanged();//通知gui,表結構發生變化
                      return;
                  case ServiceEvent.UNREGISTERING://表明有些列將被刪除
                      ref = event.getServiceReference();
                      service = this.context.getService(ref);
                      this.columns.remove(service);
                      this.fireTableStructureChanged();//通知gui,表結構發生變化
                      return;
                  }
              }

              //這個類定義一個“Family Name”這個列,以及如何按這個列的值進行排序
              class FamilyNameColumn implements FamilyInfoColumn,SortingFamilyInfoCriteria {
                  private static final String COLUMNNAME = "Family Name";
                 
                  public Object getColumnValue(FamilyInfoEntry entry) {
                      return entry.getFamilyName();
                  }
                 
                 
                  public String getColumnName() {
                      return FamilyNameColumn.COLUMNNAME;
                  }
                 
                  public String getSortFieldString() {
                      return FamilyNameColumn.COLUMNNAME;
                  }
                  public int compare(Object obj1, Object obj2) {
                      if (obj1 == obj2) {
                          return 0;
                      }
                      FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
                      FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
                     
                      return en1.getFamilyName().compareTo(en2.getFamilyName());
                  }
                 
              }
              //這個類定義一個“Family Population”這個列,以及如何按這個列的值進行排序
              class FamilyPopulationColumn implements FamilyInfoColumn, SortingFamilyInfoCriteria {
                  private static final String COLUMNNAME = "Family Population";
                  public Object getColumnValue(FamilyInfoEntry entry) {
                      return new Integer(entry.getPopulation());
                  }
                  public String getColumnName() {
                      return FamilyPopulationColumn.COLUMNNAME;
                  }
                 
                  public String getSortFieldString() {
                      return FamilyPopulationColumn.COLUMNNAME;
                  }
                 
                  public int compare(Object obj1, Object obj2) {
                      if (obj1 == obj2) {
                          return 0;
                      }
                      FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
                      FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
                     
                      return en1.getPopulation() - en2.getPopulation();
                  }
              }
             
              //這個類定義一個“Family Income”這個列,以及如何按這個列的值進行排序
              class FamilyIncomeColumn implements FamilyInfoColumn, SortingFamilyInfoCriteria {
                  private static final String COLUMNNAME = "Family Income";
                  public Object getColumnValue(FamilyInfoEntry entry) {
                      return new Integer(entry.getIncomePerYear());
                  }
                  public String getColumnName() {
                      return FamilyIncomeColumn.COLUMNNAME;
                  }
                 
                 
                  public String getSortFieldString() {
                      return FamilyIncomeColumn.COLUMNNAME;
                  }
                  public int compare(Object obj1, Object obj2) {
                      if (obj1 == obj2) {
                          return 0;
                      }
                      FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
                      FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
                     
                      return en1.getIncomePerYear() - en2.getIncomePerYear();
                  }
                 
              }
          }
           
          與(五)相比,最大的不同就是表結構的“列”是通過查找所有類型為FamilyInfoColumn的服務對象而組成的。而通過framework提供的服務偵聽機制(即實現ServiceListener接口并注冊到framework中),bundle能夠獲得該類服務對象的動態事件通知,如果該事件是新服務注冊,則添加一個顯示列,如果是服務被注銷,則刪除對應的顯示列。
           
          下面是bundle的manifest文件
          Manifest-Version: 1.0
          Bundle-SymbolicName: com.bajie.test.family.model
          Bundle-Name: family model
          Bundle-Version: 1.0
          Bundle-Vendor: LiMing
          Bundle-Activator: com.bajie.test.family.model.impl.FamilyDatabase
          Import-Package: org.osgi.framework;version=1.3,com.bajie.test.family.model
          Export-Package: com.bajie.test.family.model;version=1.0
          從中我們看到com.bajie.test.family.model這個package被export出來,這樣其他bundle就能夠import這個package,并根據FamilyInfoEntry所提供的基本內容提供一些額外的處理結果,從而產生新列(FamilyInfoColumn)以及排序方法(SortingFamilyInfoCriteria),比如家庭人均年收入。

          下面來看看gui bundle,它只包含一個package
          package com.bajie.test.family.gui;
          import java.awt.BorderLayout;
          import java.awt.Dimension;
          import java.awt.GridLayout;
          import java.awt.event.ActionEvent;
          import java.awt.event.ActionListener;
          import java.awt.event.ItemEvent;
          import java.awt.event.ItemListener;
          import java.util.Hashtable;
          import javax.swing.JButton;
          import javax.swing.JComboBox;
          import javax.swing.JFrame;
          import javax.swing.JLabel;
          import javax.swing.JPanel;
          import javax.swing.JScrollPane;
          import javax.swing.JTable;
          import org.osgi.framework.BundleActivator;
          import org.osgi.framework.BundleContext;
          import org.osgi.framework.Constants;
          import org.osgi.framework.ServiceEvent;
          import org.osgi.framework.ServiceListener;
          import org.osgi.framework.ServiceReference;
          import com.bajie.test.family.model.FamilyInfoDatabase;
          import com.bajie.test.family.model.SortingFamilyInfoCriteria;
          public class FamilyInfoGui implements BundleActivator, ActionListener,
                  ItemListener, ServiceListener {
              private JFrame mainFrame;
              private JPanel contentPanel;
              private JTable familiesTable;
              private JScrollPane familiesTableScrollPane;
              private JPanel sortedByPanel = new JPanel(new GridLayout(1, 2));
              private JLabel sortedByLabel = new JLabel("Sorted By: ");
              private JComboBox sortedByList = null;
              private JPanel commandPanel = new JPanel(new GridLayout(1, 3));
              private JButton addEntry = new JButton("Add");
              private JButton deleteEntry = new JButton("Delete");
              private JButton updateEntry = new JButton("Update");
              private Hashtable sortingFields = new Hashtable();
              private BundleContext context;
              FamilyInfoDatabase database = null;
              public void start(BundleContext context) throws Exception {
                  this.context = context;
                  //查找所有注冊類型為FamilyInfoDatabase的服務對象。在我們這個例子,它是由上面給出的model bundle注冊的
                  ServiceReference databaseServiceRef = context
                          .getServiceReference(FamilyInfoDatabase.class.getName());
                  if (databaseServiceRef == null) {
                      System.out.println("No database service is registered.");
                      return;
                  }
           //這個服務對象將成為JTable的數據model
                  this.database = (FamilyInfoDatabase) context
                          .getService(databaseServiceRef);
                  if (this.database == null) {
                      System.out.println("Can not get database object");
                      return;
                  }
                  //查找所有注冊類型為SortingFamilyInfoCriteria的服務對象。
                  ServiceReference[] sortingCriteria = context.getServiceReferences(
                          SortingFamilyInfoCriteria.class.getName(), null);
                  sortedByList = new JComboBox();
                  SortingFamilyInfoCriteria criterion = null;
                  if (sortingCriteria != null) {
                      for (int i = 0; i < sortingCriteria.length; i++) {
                          criterion = (SortingFamilyInfoCriteria) context
                                  .getService(sortingCriteria[i]);
                          if (criterion != null) {
                //每個服務對象將對應一種排序方法,并加入到下拉列表中
                              sortedByList.addItem(criterion.getSortFieldString());
                              this.sortingFields.put(criterion.getSortFieldString(),
                                      criterion);
                          }
                      }
                  }
           //注冊服務偵聽器,該偵聽器專門偵聽SortingFamilyInfoCriteria服務對象的動態(主要是增加和刪除)
                  context.addServiceListener(this, "(" + Constants.OBJECTCLASS + "="
                          + SortingFamilyInfoCriteria.class.getName() + ")");
                  sortedByList.addItemListener(FamilyInfoGui.this);
                  //construct gui
                  Runnable r = new Runnable() {
                      public void run() {
                          contentPanel = new JPanel();
                          familiesTableScrollPane = new JScrollPane();
            //獲得的FamilyInfoDatabase對象成為gui中JTable的model
                          familiesTable = new JTable(database);
                          familiesTableScrollPane.setViewportView(familiesTable);
                          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(500, 600));
                          mainFrame.show();
                      }
                  };
                  Thread t = new Thread(r);
                  t.start();
              }
              public void stop(BundleContext context) throws Exception {
                  if (this.mainFrame != null)
                      this.mainFrame.dispose();
              }
              public void actionPerformed(ActionEvent event) {
              }
              public void itemStateChanged(ItemEvent event) {
                  if (event.getSource() == this.sortedByList) {
                      SortingFamilyInfoCriteria criterion = (SortingFamilyInfoCriteria) this.sortingFields
                              .get(event.getItem());
                      if (criterion == null)
                          return;
                      this.database.sort(criterion);
                      this.familiesTable.repaint();
                  }
              }
              public void serviceChanged(ServiceEvent event) {
                  switch (event.getType()) {
                  case ServiceEvent.MODIFIED:
                      return;
                  case ServiceEvent.REGISTERED://有新的排序方法注冊到framework當中
                      ServiceReference ref = event.getServiceReference();
                      SortingFamilyInfoCriteria criterion = (SortingFamilyInfoCriteria) this.context
                              .getService(ref);
                      if (criterion != null) {
            //把新的排序方法加入到下拉列表中
                          sortedByList.addItem(criterion.getSortFieldString());
                          this.sortingFields.put(criterion.getSortFieldString(),
                                  criterion);
                      }
                      return;
                  case ServiceEvent.UNREGISTERING://一個現有的排序方法將被從framework被取消
                      ref = event.getServiceReference();
                      criterion = (SortingFamilyInfoCriteria) this.context
                              .getService(ref);
                      if (criterion != null) {
            //把該排序方法從下拉列表中刪除
                          sortedByList.removeItem(criterion.getSortFieldString());
                          this.sortingFields.remove(criterion);
                      }
                      return;
                  }
              }
          }
           
          與(五)相比不同的地方是,這個gui的table model以及排序的方法,都是通過查詢service對象獲得。
           
          manifest文件如下:
          Manifest-Version: 1.0
          Bundle-SymbolicName: com.bajie.test.family.gui
          Bundle-Name: family gui
          Bundle-Version: 1.0
          Bundle-Vendor: LiMing
          Bundle-Activator: com.bajie.test.family.gui.FamilyInfoGui
          Import-Package: org.osgi.framework;version=1.3,com.bajie.test.family.model
           
          然后我們生成bundle的jar文件。分別為familymodel.jar和familygui.jar,之后我們用“in”命令把兩個bundle裝入framework。
          接著我們先啟動model bundle,然后再啟動gui bundle,我們會看到JTable中有3列,而排序方法列表中也有3個選項,完全和程序的邏輯符合。
           
          接下來,我們假設客戶需要添加顯示每個家庭的人均年收入并按其排列紀錄。要滿足這個需求,我們可以參考在(五)中做法,就是在model bundle里面再添加一個同時實現了FamilyInfoColumn和SortingFamilyInfoCriteria的類,并在bundle的啟動中作為服務注冊到framework中?不過這樣就得更新model bundle然后調用rfr命令來刷新。為什么不再裝一個補丁bundle,在這個bundle中包含了同時實現FamilyInfoColumn和SortingFamilyInfoCriteria的類,并在這個新bunle啟動時注冊產生該類的新對象作為服務注冊到framework中,這樣gui和model bundle都能偵聽到該新服務的到來(他們都實現了服務偵聽接口ServiceListener),gui上馬上就能有所體現。

          這個新bundle的代碼如下:
          package com.bajie.test.family.model.impladd;
          import org.osgi.framework.BundleActivator;
          import org.osgi.framework.BundleContext;
          import com.bajie.test.family.model.FamilyInfoColumn;
          import com.bajie.test.family.model.FamilyInfoEntry;
          import com.bajie.test.family.model.SortingFamilyInfoCriteria;
          public class FamilyIncomePerPerson implements BundleActivator {
              public void start(BundleContext context) throws Exception {
           //注冊一個新的服務,服務的類型既為FamilyInfoColumn,也是SortingFamilyInfoCriteria
                  String[] clazzes = new String[] {FamilyInfoColumn.class.getName(),SortingFamilyInfoCriteria.class.getName()};
                  context.registerService(clazzes,new FamilyIncomePerPersonColumn(),null);
                 
              }
              public void stop(BundleContext context) throws Exception {
              }
              //這個類實現了“Income Per Person”這個列以及按該列排序的方法。
              class FamilyIncomePerPersonColumn implements FamilyInfoColumn,SortingFamilyInfoCriteria {
                  private static final String COLUMNNAME = "Income Per Person";
                 
                  public Object getColumnValue(FamilyInfoEntry entry) {
                      return new Integer(entry.getIncomePerYear()/entry.getPopulation());
                  }
                 
                 
                  public String getColumnName() {
                      return FamilyIncomePerPersonColumn.COLUMNNAME;
                  }
                 
                  public String getSortFieldString() {
                      return FamilyIncomePerPersonColumn.COLUMNNAME;
                  }
                  public int compare(Object obj1, Object obj2) {
                      if (obj1 == obj2) {
                          return 0;
                      }
                      FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
                      FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
                     
                      return en1.getIncomePerYear()/en1.getPopulation() - en2.getIncomePerYear()/en2.getPopulation();
                  }
                 
              }
          }
           
          manifest文件如下:
          Manifest-Version: 1.0
          Bundle-SymbolicName: com.bajie.test.family.modeladd
          Bundle-Name: family model add
          Bundle-Version: 1.0
          Bundle-Vendor: LiMing
          Bundle-Activator: com.bajie.test.family.model.impladd.FamilyIncomePerPerson
          Import-Package: org.osgi.framework;version=1.3,com.bajie.test.family.model
           
          打包安裝到framework后,啟動該bundle,我們就會在gui上看到新的列已經被添加,而且排序列表中增加了一個新的排序選項。
          這個結果,完全符合需求的意圖。
          如果我們用stp命令停止這個bundle,我們在gui上就會發現,新列消失,而且排序列表中對應選項也沒有了。這就是service帶來的動態效果。不過,如果我們的model發生了一些實質的變化,比如FamilyInfoEntry需要添加一個“地址”列,那么model bundle就要更新,進而gui bundle以及使用到這個類型的bundle都需要通過rfr命令刷新。
           
          好了,對扶貧助手的分析就此打住,我們總結一下,通過程序可以看到注冊服務一點都不復雜。最簡單的情況我們只需要提供一個java類型名稱,以及實現這個類型的一個java對象就可以了,
          不需要提供復雜的類型描述,比如xml描述文件。而使用服務的bundle通過類型名稱就輕而易舉的查找到相關的服務對象。
           
          到此,osig介紹系列就要結束了,只希望這個系列能夠把你引入到osgi的門口,其后面的精彩世界就看你的興趣了。
          就我個人的關注和理解,今年是osgi很重要的一年。JSR249今年應該投票,如果osgi入選,那么osgi將成為高端手機中java體系結構的重要組成部分。
          在汽車領域,siemensVDO已經推出了基于osgi的解決方案,聽說已經配備在BMW serials 5里面了。應該還會有更多的應用......
           
          如果你是osgi的粉絲,歡迎你來信jerrylee.li@gmail.com拍磚交流。

          posted on 2006-02-14 16:08 勤勞的蜜蜂 閱讀(5960) 評論(13)  編輯  收藏

          評論

          # re: OSGi介紹(六)OSGi的service 2006-02-15 09:50 BlueDavy

          ^_^,現在注冊服務以及使用服務的部分在osgi中還是不那么方便的,注入會讓它變得更加方便,其實好像ds是解決了部分,但還沒完全做到注入..  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2006-02-15 12:36 勤勞的蜜蜂

          ds是什么?有相關的比較文章嗎?我看看,謝謝。  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2006-02-15 13:15 BlueDavy

          OSGI中的Declartive Service  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2006-02-15 13:21 勤勞的蜜蜂

          哦,它呀。正在研究中,聽說是extension point的替代品  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service[未登錄] 2007-04-16 17:48 andy

          謝啦 樓主好幸苦 不過感覺這個例子太長 看起來有點費勁 最好能找個簡單一點的 大家看著方便 不知道您對ds有什么看法 我的郵箱是qmiao128@163.com 可以交流一下嗎  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2007-06-22 11:59 hata

          太長了 看暈了.沒理解service的機制.
          繼續看看...暈暈了.  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2007-07-05 15:36 guyong

          context.addServiceListener(this,"(" + Constants.OBJECTCLASS + "=" + FamilyInfoColumn.class.getName() + ")");
          請問一下這個給bundle添加監聽的方法中的第二個參數是什么意思?格式是固定的嗎?謝謝!
          我的郵箱:guyong1018@yahoo.com.cn  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2007-07-06 13:49 ferrari4000

          第二個參數的意思是,這個listener只偵聽服務對象滿足 instanceof(FamilyInfoColumn.class) == true的ServiceEvent.
          當有服務事件發生時,Framework會給每個注冊的listener發送消息,但是,如果服務注冊的時候,有過濾條件,它會先檢查這個事件是否滿足這個過濾條件,如果不滿足,那這個事件就不會發送到這個listener.

          osgi spec里面對這個格式進行了定義.請看第37頁@r4.core.pdf version4.01 July 6, 2006版
            回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2007-09-25 09:55 hello

          太長了,很難看得懂,感覺!
          看了幾次都看不下去!
            回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2008-07-25 10:16 mhoudg

          汗……
          樓主寫了這么多,都沒喊辛苦
          反倒是來學習的人們一個勁喊長喊累……
          這世道……  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service 2008-10-31 00:03 bacuo

          不錯不錯,感謝樓主的辛勤勞動  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service[未登錄] 2008-11-19 11:00 rex

          非常感謝作者的工作!  回復  更多評論   

          # re: OSGi介紹(六)OSGi的service[未登錄] 2008-12-12 15:07 mark

          看后受益匪淺,非常感謝樓主  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 宾阳县| 鱼台县| 达孜县| 临夏市| 江山市| 抚松县| 大连市| 嘉定区| 靖州| 多伦县| 兴海县| 西贡区| 永川市| 东台市| 萨嘎县| 嘉禾县| 呼和浩特市| 翼城县| 加查县| 岱山县| 简阳市| 房产| 团风县| 南投市| 阳东县| 锦屏县| 元阳县| 赞皇县| 望都县| 九台市| 石首市| 南陵县| 庆安县| 洪泽县| 岢岚县| 平凉市| 平乐县| 垦利县| 天津市| 尚义县| 大竹县|