OSGi介紹(六)OSGi的service
在(五)中,我們看到程序被分成多個(gè)bundle后,程序的模塊程度得到提高,而控制模塊間的耦合度由Import-Package和Export-Package來(lái)控制,相對(duì)比較靈活。另一方面程序的更新和升級(jí)的粒度變小了。誰(shuí)都知道只更新部分要比全部更新強(qiáng),尤其當(dāng)更新發(fā)生在一些需要建立昂貴的連接時(shí),細(xì)粒度會(huì)節(jié)省不少花銷(xiāo)。除了這些,我們看不到其他新鮮的東西。說(shuō)白了,也就是挖空心思想一些design pattern來(lái)劃分程序模塊。
先給出model bundle的代碼,該bundle包含兩個(gè)java package,分別是:
com.bajie.test.family.model
com.bajie.test.family.model.impl
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,這是因?yàn)槲覀兿M?dāng)數(shù)據(jù)或顯示需求變化時(shí),gui上的JTable能獲得通知,并顯示更新的結(jié)果。SortingFamilyInfoCriteria這個(gè)類(lèi)型下文會(huì)給出說(shuō)明。
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;
}
}
這個(gè)類(lèi)的結(jié)構(gòu)和在(五)中完全一樣,用來(lái)紀(jì)錄一條家庭信息。唯一不同的是,在(五)中我們把它放入了實(shí)現(xiàn)(.impl)package中,在后面給出bundle的manifest文件時(shí),我將解釋為什么要這樣改。
public String getColumnName();
}
這個(gè)類(lèi)用來(lái)描述table中的某個(gè)列。
public interface SortingFamilyInfoCriteria extends Comparator{
public String getSortFieldString();
}
這個(gè)類(lèi)將用于對(duì)家庭紀(jì)錄按某一列的值進(jìn)行排序。
import java.util.LinkedList;
import java.util.List;
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.FamilyInfoEntry;
import com.bajie.test.family.model.SortingFamilyInfoCriteria;
ServiceListener {
private LinkedList familyEntryList = new LinkedList();
return this.columns.size();
}
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);
}
return this.familyEntryList.size();
}
throws IllegalArgumentException {
}
}
throws IllegalArgumentException {
}
Arrays.sort(this.sortedValues, sortField);
}
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();
context.registerService(FamilyInfoDatabase.class.getName(),this,null);
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查找所有注冊(cè)類(lèi)型為FamilyInfoColumn的服務(wù)
//先獲得服務(wù)的引用
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]);
//通過(guò)引用獲得具體的服務(wù)對(duì)象,每一個(gè)對(duì)象都將轉(zhuǎn)化成gui中table的一列
column = (FamilyInfoColumn) context.getService(columnRefs[i]);
if (column != null) {
this.columns.add(column);
}else{
System.out.println("null service object.");
}
}
//注冊(cè)服務(wù)偵聽(tīng)器,該偵聽(tīng)器專(zhuān)門(mén)偵聽(tīng)FamilyInfoColumn服務(wù)對(duì)象的動(dòng)態(tài)(主要是增加和刪除)
context.addServiceListener(this,"(" + Constants.OBJECTCLASS + "="
+ FamilyInfoColumn.class.getName() + ")");
}
switch (event.getType()) {
case ServiceEvent.MODIFIED:
return;
case ServiceEvent.REGISTERED://表明有新的列產(chǎn)生了。
ServiceReference ref = event.getServiceReference();
Object service = this.context.getService(ref);
this.columns.add(service);
this.fireTableStructureChanged();//通知gui,表結(jié)構(gòu)發(fā)生變化
return;
case ServiceEvent.UNREGISTERING://表明有些列將被刪除
ref = event.getServiceReference();
service = this.context.getService(ref);
this.columns.remove(service);
this.fireTableStructureChanged();//通知gui,表結(jié)構(gòu)發(fā)生變化
return;
}
//這個(gè)類(lèi)定義一個(gè)“Family Name”這個(gè)列,以及如何按這個(gè)列的值進(jìn)行排序
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;
}
if (obj1 == obj2) {
return 0;
}
FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
return en1.getFamilyName().compareTo(en2.getFamilyName());
}
}
class FamilyPopulationColumn implements FamilyInfoColumn, SortingFamilyInfoCriteria {
private static final String COLUMNNAME = "Family Population";
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();
}
}
//這個(gè)類(lèi)定義一個(gè)“Family Income”這個(gè)列,以及如何按這個(gè)列的值進(jìn)行排序
class FamilyIncomeColumn implements FamilyInfoColumn, SortingFamilyInfoCriteria {
private static final String COLUMNNAME = "Family Income";
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();
}
}
}
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
下面來(lái)看看gui bundle,它只包含一個(gè)package
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.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.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.SortingFamilyInfoCriteria;
ItemListener, ServiceListener {
private JFrame mainFrame;
this.context = context;
//查找所有注冊(cè)類(lèi)型為FamilyInfoDatabase的服務(wù)對(duì)象。在我們這個(gè)例子,它是由上面給出的model bundle注冊(cè)的
ServiceReference databaseServiceRef = context
.getServiceReference(FamilyInfoDatabase.class.getName());
if (databaseServiceRef == null) {
System.out.println("No database service is registered.");
return;
}
this.database = (FamilyInfoDatabase) context
.getService(databaseServiceRef);
if (this.database == null) {
System.out.println("Can not get database object");
return;
}
ServiceReference[] sortingCriteria = context.getServiceReferences(
SortingFamilyInfoCriteria.class.getName(), null);
SortingFamilyInfoCriteria criterion = null;
if (sortingCriteria != null) {
for (int i = 0; i < sortingCriteria.length; i++) {
criterion = (SortingFamilyInfoCriteria) context
.getService(sortingCriteria[i]);
if (criterion != null) {
//每個(gè)服務(wù)對(duì)象將對(duì)應(yīng)一種排序方法,并加入到下拉列表中
sortedByList.addItem(criterion.getSortFieldString());
this.sortingFields.put(criterion.getSortFieldString(),
criterion);
}
}
}
context.addServiceListener(this, "(" + Constants.OBJECTCLASS + "="
+ SortingFamilyInfoCriteria.class.getName() + ")");
Runnable r = new Runnable() {
public void run() {
contentPanel = new JPanel();
familiesTableScrollPane = new JScrollPane();
//獲得的FamilyInfoDatabase對(duì)象成為gui中JTable的model
familiesTable = new JTable(database);
familiesTableScrollPane.setViewportView(familiesTable);
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();
}
if (this.mainFrame != null)
this.mainFrame.dispose();
}
}
if (event.getSource() == this.sortedByList) {
SortingFamilyInfoCriteria criterion = (SortingFamilyInfoCriteria) this.sortingFields
.get(event.getItem());
if (criterion == null)
return;
this.database.sort(criterion);
this.familiesTable.repaint();
}
}
switch (event.getType()) {
case ServiceEvent.MODIFIED:
return;
case ServiceEvent.REGISTERED://有新的排序方法注冊(cè)到framework當(dāng)中
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://一個(gè)現(xiàn)有的排序方法將被從framework被取消
ref = event.getServiceReference();
criterion = (SortingFamilyInfoCriteria) this.context
.getService(ref);
if (criterion != null) {
//把該排序方法從下拉列表中刪除
sortedByList.removeItem(criterion.getSortFieldString());
this.sortingFields.remove(criterion);
}
return;
}
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
接著我們先啟動(dòng)model bundle,然后再啟動(dòng)gui bundle,我們會(huì)看到JTable中有3列,而排序方法列表中也有3個(gè)選項(xiàng),完全和程序的邏輯符合。
這個(gè)新bundle的代碼如下:
package com.bajie.test.family.model.impladd;
import org.osgi.framework.BundleContext;
import com.bajie.test.family.model.FamilyInfoEntry;
import com.bajie.test.family.model.SortingFamilyInfoCriteria;
//注冊(cè)一個(gè)新的服務(wù),服務(wù)的類(lèi)型既為FamilyInfoColumn,也是SortingFamilyInfoCriteria
String[] clazzes = new String[] {FamilyInfoColumn.class.getName(),SortingFamilyInfoCriteria.class.getName()};
context.registerService(clazzes,new FamilyIncomePerPersonColumn(),null);
}
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;
}
if (obj1 == obj2) {
return 0;
}
FamilyInfoEntry en1 = (FamilyInfoEntry)obj1;
FamilyInfoEntry en2 = (FamilyInfoEntry)obj2;
return en1.getIncomePerYear()/en1.getPopulation() - en2.getIncomePerYear()/en2.getPopulation();
}
}
}
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
這個(gè)結(jié)果,完全符合需求的意圖。
不需要提供復(fù)雜的類(lèi)型描述,比如xml描述文件。而使用服務(wù)的bundle通過(guò)類(lèi)型名稱(chēng)就輕而易舉的查找到相關(guān)的服務(wù)對(duì)象。
就我個(gè)人的關(guān)注和理解,今年是osgi很重要的一年。JSR249今年應(yīng)該投票,如果osgi入選,那么osgi將成為高端手機(jī)中java體系結(jié)構(gòu)的重要組成部分。
在汽車(chē)領(lǐng)域,siemensVDO已經(jīng)推出了基于osgi的解決方案,聽(tīng)說(shuō)已經(jīng)配備在BMW serials 5里面了。應(yīng)該還會(huì)有更多的應(yīng)用......
posted on 2006-02-14 16:08 勤勞的蜜蜂 閱讀(5969) 評(píng)論(13) 編輯 收藏