<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Chasing an mobile web vision

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

    #

    OSGi介紹(六)OSGi的service

    在給出采用service方式實現(xiàn)的“扶貧助手”之前,我們稍微回顧一下上一篇的成果。
    在(五)中,我們看到程序被分成多個bundle后,程序的模塊程度得到提高,而控制模塊間的耦合度由Import-Package和Export-Package來控制,相對比較靈活。另一方面程序的更新和升級的粒度變小了。誰都知道只更新部分要比全部更新強,尤其當(dāng)更新發(fā)生在一些需要建立昂貴的連接時,細(xì)粒度會節(jié)省不少花銷。除了這些,我們看不到其他新鮮的東西。說白了,也就是挖空心思想一些design pattern來劃分程序模塊。
     
    好了,馬上就新鮮了。下面你會看到通過采用service方式來改造(五)中的程序,gui bundle在某些情況下不用重新啟動,就能直接某些適應(yīng)需求的變更!
    先給出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,這是因為我們希望當(dāng)數(shù)據(jù)或顯示需求變化時,gui上的JTable能獲得通知,并顯示更新的結(jié)果。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;
        }
    }

    這個類的結(jié)構(gòu)和在(五)中完全一樣,用來紀(jì)錄一條家庭信息。唯一不同的是,在(五)中我們把它放入了實現(xiàn)(.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();
    }
    這個類將用于對家庭紀(jì)錄按某一列的值進行排序。
    在com.bajie.test.family.model.impl這個package中包含上面抽象類和interface的實現(xiàn):
    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的服務(wù)
            context.registerService(FamilyInfoDatabase.class.getName(),this,null);
     //向framework注冊三個服務(wù),每個服務(wù)的類型既為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的服務(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]);
         //通過引用獲得具體的服務(wù)對象,每一個對象都將轉(zhuǎn)化成gui中table的一列
                column = (FamilyInfoColumn) context.getService(columnRefs[i]);
                if (column != null) {
                    this.columns.add(column);
                }else{
                    System.out.println("null service object.");
                }
            }

     //注冊服務(wù)偵聽器,該偵聽器專門偵聽FamilyInfoColumn服務(wù)對象的動態(tài)(主要是增加和刪除)
            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://表明有新的列產(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;
            }
        }

        //這個類定義一個“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();
            }
           
        }
    }
     
    與(五)相比,最大的不同就是表結(jié)構(gòu)的“列”是通過查找所有類型為FamilyInfoColumn的服務(wù)對象而組成的。而通過framework提供的服務(wù)偵聽機制(即實現(xiàn)ServiceListener接口并注冊到framework中),bundle能夠獲得該類服務(wù)對象的動態(tài)事件通知,如果該事件是新服務(wù)注冊,則添加一個顯示列,如果是服務(wù)被注銷,則刪除對應(yīng)的顯示列。
     
    下面是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,并根據(jù)FamilyInfoEntry所提供的基本內(nèi)容提供一些額外的處理結(jié)果,從而產(chǎn)生新列(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的服務(wù)對象。在我們這個例子,它是由上面給出的model bundle注冊的
            ServiceReference databaseServiceRef = context
                    .getServiceReference(FamilyInfoDatabase.class.getName());
            if (databaseServiceRef == null) {
                System.out.println("No database service is registered.");
                return;
            }
     //這個服務(wù)對象將成為JTable的數(shù)據(jù)model
            this.database = (FamilyInfoDatabase) context
                    .getService(databaseServiceRef);
            if (this.database == null) {
                System.out.println("Can not get database object");
                return;
            }
            //查找所有注冊類型為SortingFamilyInfoCriteria的服務(wù)對象。
            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) {
          //每個服務(wù)對象將對應(yīng)一種排序方法,并加入到下拉列表中
                        sortedByList.addItem(criterion.getSortFieldString());
                        this.sortingFields.put(criterion.getSortFieldString(),
                                criterion);
                    }
                }
            }
     //注冊服務(wù)偵聽器,該偵聽器專門偵聽SortingFamilyInfoCriteria服務(wù)對象的動態(tài)(主要是增加和刪除)
            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當(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://一個現(xiàn)有的排序方法將被從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個選項,完全和程序的邏輯符合。
     
    接下來,我們假設(shè)客戶需要添加顯示每個家庭的人均年收入并按其排列紀(jì)錄。要滿足這個需求,我們可以參考在(五)中做法,就是在model bundle里面再添加一個同時實現(xiàn)了FamilyInfoColumn和SortingFamilyInfoCriteria的類,并在bundle的啟動中作為服務(wù)注冊到framework中?不過這樣就得更新model bundle然后調(diào)用rfr命令來刷新。為什么不再裝一個補丁bundle,在這個bundle中包含了同時實現(xiàn)FamilyInfoColumn和SortingFamilyInfoCriteria的類,并在這個新bunle啟動時注冊產(chǎn)生該類的新對象作為服務(wù)注冊到framework中,這樣gui和model bundle都能偵聽到該新服務(wù)的到來(他們都實現(xiàn)了服務(wù)偵聽接口ServiceListener),gui上馬上就能有所體現(xiàn)。

    這個新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 {
     //注冊一個新的服務(wù),服務(wù)的類型既為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 {
        }
        //這個類實現(xiàn)了“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上看到新的列已經(jīng)被添加,而且排序列表中增加了一個新的排序選項。
    這個結(jié)果,完全符合需求的意圖。
    如果我們用stp命令停止這個bundle,我們在gui上就會發(fā)現(xiàn),新列消失,而且排序列表中對應(yīng)選項也沒有了。這就是service帶來的動態(tài)效果。不過,如果我們的model發(fā)生了一些實質(zhì)的變化,比如FamilyInfoEntry需要添加一個“地址”列,那么model bundle就要更新,進而gui bundle以及使用到這個類型的bundle都需要通過rfr命令刷新。
     
    好了,對扶貧助手的分析就此打住,我們總結(jié)一下,通過程序可以看到注冊服務(wù)一點都不復(fù)雜。最簡單的情況我們只需要提供一個java類型名稱,以及實現(xiàn)這個類型的一個java對象就可以了,
    不需要提供復(fù)雜的類型描述,比如xml描述文件。而使用服務(wù)的bundle通過類型名稱就輕而易舉的查找到相關(guān)的服務(wù)對象。
     
    到此,osig介紹系列就要結(jié)束了,只希望這個系列能夠把你引入到osgi的門口,其后面的精彩世界就看你的興趣了。
    就我個人的關(guān)注和理解,今年是osgi很重要的一年。JSR249今年應(yīng)該投票,如果osgi入選,那么osgi將成為高端手機中java體系結(jié)構(gòu)的重要組成部分。
    在汽車領(lǐng)域,siemensVDO已經(jīng)推出了基于osgi的解決方案,聽說已經(jīng)配備在BMW serials 5里面了。應(yīng)該還會有更多的應(yīng)用......
     
    如果你是osgi的粉絲,歡迎你來信jerrylee.li@gmail.com拍磚交流。

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

    OSGi介紹(五)兩個bundle

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

    posted @ 2006-02-14 16:02 勤勞的蜜蜂 閱讀(4391) | 評論 (3)編輯 收藏

    OSGi介紹(四)第一個bundle

    先給出“扶貧助手”的第一種改造,我稱之為“直接型”,請看:

    package aa.bb.cc;
    //需要import osgi的核心package
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    //實現(xiàn)了BundleActivator
    public class FamilyInfo implements BundleActivator {
     
    private String familyName;
     
    private int population;
     
    private int incomePerYear;
     省略了getter和setter方法 
     
    public String toString() {
      
      
    return "Family: " + this.familyName + ", population: " + this.population + ", income: " + this.incomePerYear;
     }

     
     
    public int getIncomePerMember(){
      
    return (int)(this.incomePerYear/this.population);
     }

     
    public static void sortByIncomePerYear(FamilyInfo[] families){
      FamilyInfo temp 
    = null;
      
    for(int i = 0; i < families.length -1; i ++){
       
    for(int j = i + 1; j < families.length; j ++){
        
        
    if(families[i].getIncomePerYear() > families[j].getIncomePerYear()){
         temp 
    = families[i];
         families[i] 
    = families[j];
         families[j] 
    = temp;
        }

       }

      }

      
     }

     
    public static void sortByIncomePerMember(FamilyInfo[] families){
      FamilyInfo temp 
    = null;
      
    for(int i = 0; i < families.length -1; i ++){
       
    for(int j = i + 1; j < families.length; j ++){
        
        
    if(families[i].getIncomePerMember() > families[j].getIncomePerMember()){
         temp 
    = families[i];
         families[i] 
    = families[j];
         families[j] 
    = temp;
        }

       }

      }

      
      
     }

     
    //在framework每次啟動該bundle的時候該方法會被framework調(diào)用執(zhí)行。
     public void start(BundleContext context) throws Exception {
      FamilyInfo[] families 
    = new FamilyInfo[3];
      families[
    0= new FamilyInfo();
      families[
    0].setFamilyName("Zhang");
      families[
    0].setPopulation(3);
      families[
    0].setIncomePerYear(1200);
      families[
    1= new FamilyInfo();
      families[
    1].setFamilyName("Li");
      families[
    1].setPopulation(6);
      families[
    1].setIncomePerYear(1800);
      families[
    2= new FamilyInfo();
      families[
    2].setFamilyName("Liu");
      families[
    2].setPopulation(4);
      families[
    2].setIncomePerYear(1500);
      FamilyInfo.sortByIncomePerYear(families);
      
    for(int i = 0; i < families.length; i ++){
       System.out.println(families[i].toString());
      }

      FamilyInfo.sortByIncomePerMember(families);
      
    for(int i = 0; i < families.length; i ++){
       System.out.println(families[i].toString());
      }

     }

     
    //在framework停止該bundle時,該方法將被framework調(diào)用
     public void stop(BundleContext context) throws Exception {
     }

    }


    看到代碼的區(qū)別了嗎?我在不同之處都標(biāo)注了注釋。其實,從說白了,就是實現(xiàn)了org.osgi.framework.BundleActivator這個接口。
    當(dāng)然,細(xì)心的話,你會發(fā)現(xiàn)這個bundle沒有public static void main(String[] args)方法了。那么它怎么被啟動呢?這個就是bundle的奧秘所在。不過,如果你了解java的class loading機制以及reflection技術(shù),你立馬會明白這個bundle的運行機制。這兩項技術(shù)廣泛應(yīng)用于j2ee(對吧?我得承認(rèn),j2ee的經(jīng)驗不多,呵呵)以及java的plugin機制。
    簡單說來,java.lang.Class這個類有一個方法:
    public Object newInstance()throws InstantiationException,IllegalAccessException
    針對上面的“扶貧助手”bundle而言,framework只要通過ClassLoader找到aa.bb.cc.FamilyInfo.class并加載后,就可以通過newInstance()方法創(chuàng)建一個BundleActivator的實例,然后調(diào)用public void start(BundleContext context)方法,就完成了啟動bundle的動作了。之后,調(diào)用public
    void stop(BundleContext context)方法來停止bundle
    如果你接著問,framework怎么知道這個bundle里面的BundleActivator是哪個類呢?嗯,問到點子上了。這就涉及到下面我們要講的bundle的部署了。在上一篇給出的bundle定義中指出,Jar文件是bundle的唯一格式,也就是說,我們要運行bundle,必須把代碼打成jar文件。而jar文件可以帶有manifest文件,這個文件對bundle是不可缺少的。OSGi規(guī)范里面,通過定義一系列適用于bundle的manifest關(guān)鍵字(bundle manifest header)來擴展manifest文件。
    比如,開發(fā)人員在manifest中添加下面一行:
    Bundle-Activator: aa.bb.cc.FamilyInfo
    這樣,在bundle被部署到framework后,framework就可以通過讀取manifest的關(guān)鍵字來獲得BundleActivator的具體實現(xiàn)類名,并通過reflection機制產(chǎn)生BundleActivator的實例。
    這里就給出扶貧助手的manifest的一個例子:

    Manifest-Version: 1.0  
    Bundle-SymbolicName: aa.bb.cc.family //osgi specification 4強制要求的關(guān)鍵字,每個bundle都必須有唯一的symbolic name
    Bundle-Name: Family Info Manager        //bundle的名稱
    Bundle-Version: 
    1.0   //bundle的版本號
    Bundle-Activator: aa.bb.cc.FamilyInfo   //指明BundleActivator的實現(xiàn)類名
    Import-Package: org.osgi.framework
    ;version=1.3   //列出該bundle需要從其他bundle所引入的
                                                                         //package(s)(提供該package的bundle必須在其
                                                                         //manifest中有Export-Package: 
                                                                         //org.osgi.framework
    ;version=1.3)

    然后我們用jdk自帶的jar工具,來生成bundle jar文件。這樣,第一個bundle就完成了,您可以下載一個開源的framework安裝這個bundle試一試。在framework上嘗試對該bundle的啟動和停止,輸出的結(jié)果應(yīng)該和原先的java application是一樣的,然后您還可以在那個start(context)的方法中,再增加一條記錄,重新打包,然后通過framework的update功能,就能夠在不重新啟動framework的情況下升級該bundle,我就暫時偷懶不針對具體framework來給出操作的方法了,先給您自己先摸索了(當(dāng)然您也可以偷懶,因為后面我會結(jié)合具體framework深入講述的)。
    好了,說完代碼的改造,再看看改造所帶來的程序設(shè)計結(jié)構(gòu)變化:那~~~就~~~~是~~~~沒變化!因此我把這種原封不動的改造方法稱為“直接型”,用這種直接法,我們可以輕易的把一個java應(yīng)用程序改造成bundle。而這種改造目前能看到的好處就是bundle的“熱”升級。那怎樣能更漂亮些呢?在下一篇中,我會進一步改造這個扶貧助手成為兩個bundle,看看bundle的合作將會帶來怎樣的精彩效果

    posted @ 2006-02-14 15:46 勤勞的蜜蜂 閱讀(5533) | 評論 (4)編輯 收藏

    OSGi介紹(三)OSGi service platform的體系結(jié)構(gòu)

    先讓我們來看看OSGi service platform的體系結(jié)構(gòu)。另外要說明的是,我在后面的文章中,將采用framework來代替OSGi service platfrom,這樣比較簡便。
    下面這張圖來自O(shè)SGi Alliance的主頁(http://www.osgi.org/
     
    OSGi Service Platform Architecture

    層次很分明吧。放到我們假想的案例中,OS&Hardware可以對應(yīng)為PDA的硬件和操作系統(tǒng),您可以想象它是Intel xscacle + Microsoft window mobile,或者是Arm + embedded Linux
    而Execution Environment當(dāng)然是我們上次提到的CVM + CDC + FP + PP,有這個jvm的配置運行framework就綽綽有余了。而再往上,就是我們要重點學(xué)習(xí)和分析的OSGi framework了。而Modules, Life Cycle, Service Registry, Services和Security是從不同的5個角度來劃分framework所具備的功能,后面我將會從除了Security外的四個方面分別結(jié)合我們的假設(shè)場景來分析。而體系結(jié)構(gòu)的最上層是符合OSGi framework接口標(biāo)準(zhǔn)的應(yīng)用程序,也就是OSGi世界中有名的“bundle”。

    下面來看看OSGi規(guī)范是如何定義一個bundle的。在r4規(guī)范的第27頁中大致這樣描述到:Framework定義了模塊(modularization)的單元,叫作bundle。Bundle實際就是一個具有jar(Java ARchive)格式的文件,其中包含了java的class文件和其他資源文件(比如圖標(biāo),配置文件等等)。Bundle可以在自己的manifest文件中說明自己能夠提供哪些java包,其他bundle如果在自己的manifest文件中指定了它需要這個包,那他們之間就可能產(chǎn)生java包的依賴關(guān)系,這樣多個bundle之間就可以共享java包。值得注意的是,bundle是能夠在framework中部署的唯一格式。下面給出原文的描述:
    A bundle is a JAR file that:
    ? Contains the resources necessary to provide some functionality. These resources may be class files for the Java programming language, as well as other data such as HTML files, help files, icons, and so on. A bundle JAR file can also embed additional JAR files that are available as resources and classes. This is however not recursive.
    ? Contains a manifest file describing the contents of the JAR file and providing information about the bundle. This file uses headers to specify information that the Framework needs to install correctly and activate a bundle. For example, it states dependencies on other resources, such as Java packages, that must be available to the bundle before it can run.
    ? Can contain optional documentation in the OSGI-OPT directory of the JAR file or one of its sub-directories. Any information in this directory is optional. For example, the OSGI-OPT directory is useful to store the source code of a bundle. Management systems may remove this information to save storage space in the OSGi Service Platform.

    framework的modules這一方面功能將主要負(fù)責(zé)bundle的安裝部署,更新和卸載,以及bundle在設(shè)備的物理存儲(如果有的話)。在這個層次,每個bundle都是獨立的,它的安裝,升級和卸載完全不依賴任何其他bundle,這點framework提供了強大的隔離性。Life Cycle專門負(fù)責(zé)對bundle的解析(比如關(guān)聯(lián)兩個有相互依賴關(guān)系的bundle),啟動(相當(dāng)于運行應(yīng)用程序)和停止(相當(dāng)于停止應(yīng)用程序)。這個層次中,bundle間的邏輯關(guān)系被創(chuàng)建起來,這些關(guān)系能否成功的創(chuàng)建,將會直接影響bundle的成功解析和啟動。Service Registry可以認(rèn)為是一個數(shù)據(jù)庫,bundle啟動后,可以向這個數(shù)據(jù)庫注冊它動態(tài)提供的服務(wù)。只要bundle不被停止,且bundle不主動撤銷注冊的服務(wù),這個服務(wù)將一直保存在這個數(shù)據(jù)庫中供其它bundle來查詢和使用。而Services就是由bundle運行時提供的具體服務(wù)對象,這些服務(wù)對象的存在,使得framework具有極其動態(tài)的特征,并為framework運行時提供靈活強大的功能。
    另外,根據(jù)OSGi Alliance的說法,OSGi的運行平臺包括了j2me(kvm + cldc + midp, cvm + cdc+fp), j2se, j2ee。不過,我個人還是覺得目前的midp規(guī)范還太弱,OSGi要想運行在上面,很多功能實現(xiàn)起來都比較不爽。

    好,有了對framework結(jié)構(gòu)層次的皮毛認(rèn)識,下面我們就開始著手改造那個“扶貧助手”的程序,使其變成OSGi的bundle(s),然后從上面提到的4個方面來分析framework的機制。
    這里,我先給出“扶貧助手”的java application模擬程序代碼:

    package aa.bb.cc;

    public class FamilyInfo {
     
    private String familyName; //家庭名稱
     private int population; //人口數(shù)量
     private int incomePerYear; //家庭年收入

      …..
    //省略了getter和setter方法

    //獲得家庭人均年收入
     public int getIncomePerMember(){
      
    return (int)(this.incomePerYear/this.population);
     }


     
    public String toString() {
      
      
    return "Family: " + this.familyName + ", population: " + this.population + ", income: " + this.incomePerYear;
     }

     
    //按家庭年收入又低到高排序
     public static void sortByIncomePerYear(FamilyInfo[] families){
      FamilyInfo temp 
    = null;
      
    for(int i = 0; i < families.length -1; i ++){
       
    for(int j = i + 1; j < families.length; j ++){
        
        
    if(families[i].getIncomePerYear() > families[j].getIncomePerYear()){
         temp 
    = families[i];
         families[i] 
    = families[j];
         families[j] 
    = temp;
        }

       }

      }

      
     }


     
    //按家庭人均年收入由低到高排序
     public static void sortByIncomePerMember(FamilyInfo[] families){
      FamilyInfo temp 
    = null;
      
    for(int i = 0; i < families.length -1; i ++){
       
    for(int j = i + 1; j < families.length; j ++){
        
        
    if(families[i].getIncomePerMember() > families[j].getIncomePerMember()){
         temp 
    = families[i];
         families[i] 
    = families[j];
         families[j] 
    = temp;
        }

       }

      }

      
     }


     
    public static void main(String[] args){
      FamilyInfo[] families 
    = new FamilyInfo[3];
      families[
    0= new FamilyInfo();
      families[
    0].setFamilyName("Zhang");
      families[
    0].setPopulation(3);
      families[
    0].setIncomePerYear(1200);
      families[
    1= new FamilyInfo();
      families[
    1].setFamilyName("Li");
      families[
    1].setPopulation(6);
      families[
    1].setIncomePerYear(1800);
      families[
    2= new FamilyInfo();
      families[
    2].setFamilyName("Liu");
      families[
    2].setPopulation(4);
      families[
    2].setIncomePerYear(1500);
      FamilyInfo.sortByIncomePerYear(families);
      
    for(int i = 0; i < families.length; i ++){
       System.out.println(families[i].toString());
      }

      FamilyInfo.sortByIncomePerMember(families);
      
    for(int i = 0; i < families.length; i ++){
       System.out.println(families[i].toString());
      }

      
     }

    }


     

    posted @ 2006-02-14 15:42 勤勞的蜜蜂 閱讀(5176) | 評論 (3)編輯 收藏

    osgi介紹(二)一個假想的實例

    如何分析OSGi service platform的機制?給出幾個硬生生的例子,然后分析一下
    代碼?那還不如你自己看書看規(guī)范好了。因此,我覺得還是結(jié)合一個應(yīng)用實例來分析會更
    容易理解,當(dāng)然,是一個假想的應(yīng)用實例。用怎樣一個實例呢?嗯......

    幾個月前,一個中學(xué)同學(xué)打電話給我說他們要在PDA上開發(fā)一個簡單的應(yīng)用程序來臨時紀(jì)
    錄工作的結(jié)果,并向我咨詢,這種開發(fā)的難度和周期。這事啟發(fā)我了,就以PDA的應(yīng)用為
    背景,讓我們來假想一個場景,從而來比較傳統(tǒng)的應(yīng)用模型與采用OSGi的應(yīng)用模型有怎樣
    的區(qū)別。

    我這樣想象:
    小李是一個軟件工程師,在一家專門為PDA開發(fā)應(yīng)用程序和解決方案的公司工作。最近,
    他剛為公司的一個客戶開發(fā)完成了一套運行在PDA的JAVA應(yīng)用程序,我們不要關(guān)心PDA是
    什么硬件配置,只要知道它配備了JVM(cvm) + CDC以及PP和文件系統(tǒng)(呵呵設(shè)備還是比較
    強勁的)。而這個客戶是一個慈善機構(gòu),該機構(gòu)人員攜帶PDA進入偏遠(yuǎn)山區(qū)收集生活困難
    家庭的信息,以準(zhǔn)備進行資助。而這套程序?qū)簳r把家庭信息保存在PDA中,并隨時供
    用戶查詢修改。用戶使用一個月后,反饋非常好,但是,他們有新需求了,說原來只是想紀(jì)錄
    信息就成了,現(xiàn)在希望能給出一些排序功能,比如按家庭年收入對紀(jì)錄進行排序.

    接到這個需求,小李一看,這個簡單,只要增加一個排序方法就可以了,讓我們假設(shè)他使用了如下
    數(shù)據(jù)結(jié)構(gòu)來紀(jì)錄家庭信息:

    Class FamilyInfo {

     
    private String familyName;//家庭名稱

     
    private int population; //人口數(shù)量

     
    private int incomePerYear; //年收入

     .(省略Getter和Setter方法)
    }


     

    為了滿足這個需求,小李決定添加一個靜態(tài)的排序方法:

    public static FamilyInfo[] sortByIncomePerYear(FamilyInfo[] familyInfos){
     
    //根據(jù)incomePerYear的值進行冒泡排序。
    }



    把相關(guān)連部分修改完畢后,小李重新制作了安裝包和啟動腳本,發(fā)送給客戶,不管客戶如何操作
    總之,原來的PDA程序必須卸載,新程序必須拷貝到PDA上再次執(zhí)行安裝,重新啟動運行。

    又過了一陣,客戶說,要求提供按人均年收入進行排序,然后同樣的事情又發(fā)生了......

    幾個輪次下來,小李發(fā)現(xiàn),客戶的需求還在增加,他們可能要求增加一個字段,記錄目前該
    家庭得到的資助額,還可能添加按收入范圍查詢紀(jì)錄等等,事情還遠(yuǎn)沒有結(jié)束。

    如何改進這個情況呢?當(dāng)然,改進涉及多方面,比如從軟件本身出發(fā),可以使用合適的design
    pattern重新設(shè)計程序的體系結(jié)構(gòu),使得程序更易于擴展,關(guān)于這一點,有太多的討論了,我就不
    摻和了。還有從部署方面說,配置,安裝和卸載程序,對最終用戶往往是一項mission impossible,
    能否讓應(yīng)用程序自己升級,而用戶只要點擊一個"升級"來觸發(fā)這個過程而已......

    我想你當(dāng)然知道我給的答案:OSGi,OSGi,OSGi!!!!

    posted @ 2006-02-14 15:39 勤勞的蜜蜂 閱讀(4684) | 評論 (3)編輯 收藏

    osgi介紹(一)什么是osgi

    過于的一年多,在和很多it屆的同學(xué)及朋友見面時,他們總會問我最近在做什么。“OSGi!”,我不加思索的回答。到目前為止,對這個單詞得到的反應(yīng)都沒有超出“這是什么?”,“我沒有聽說過”,“噢,能具體點嗎?”等等。而我的回答更讓他們糊涂,最后,大家干脆放棄這個話題,轉(zhuǎn)到買房,運動等等更能體現(xiàn)聚會實質(zhì)的問題上。不過最近,我一直在思考這個問題,下次再遇到這種情況時,該如何去表達(dá)才能讓也是it屆的哥們姐們能迅速的理解這個領(lǐng)域的范圍呢?要知道,技術(shù)人員往往不善于表達(dá),我們已經(jīng)習(xí)慣了和業(yè)內(nèi)人士用行話交流。

    關(guān)于這個問題,我訪問了OSGi Alliance的網(wǎng)站,在里面的faqs中,找到了我想要的東西。實際上,正如faqs中所解答的,OSGi涵蓋了太多的范圍,簡單的兩三句話是無法說清楚的。而我這里指的OSGi從技術(shù)的角度,應(yīng)該說是“OSGi service platform ”,faqs中這樣解釋OSGi service platform(http://www.osgi.org/about/faqs.asp?section=1#q19) :
    The OSGi service platform delivers an open, common architecture for service providers, developers, software vendors, gateway operators and equipment vendors to develop, deploy and manage services in a coordinated fashion. .......(以下省略上千英文單詞)

    好長!不過第一句話就已經(jīng)能總結(jié)陳詞了,“OSGi service platform是一個開放并且提供統(tǒng)一接口標(biāo)準(zhǔn)的體系框架,基于這個體系框架,服務(wù)提供商,程序開發(fā)人員,軟件提供商,服務(wù)網(wǎng)管運營商,設(shè)備提供商能夠協(xié)調(diào)地聯(lián)合起來開發(fā),部署以及管理向用戶提供的各種服務(wù)。”還需要提到的是OSGi service platform是一個基于Java的platform。

    OSGi的提出和誕生之初,其目的主要是能夠靈活方便并遠(yuǎn)程管理互聯(lián)的網(wǎng)絡(luò)嵌入設(shè)備(聽說是1997年左右提出,與Jini有深厚淵源)。隨著硬件設(shè)備的能力不斷提高,java技術(shù)的日益普及,尤其J2ME的壯大,現(xiàn)實應(yīng)用的需求也不斷擴大和推進,一個統(tǒng)一的標(biāo)準(zhǔn)變得非常的必要。OSGi Alliance就在這樣的背景下成立了。從1999年成立以來,OSGi Alliance已經(jīng)針對這個service platform發(fā)布了4版規(guī)范,其中r4是2005年10月份剛剛發(fā)布。

    目前有不少公司對OSGi service platform推出了自己的實現(xiàn),象ibm的smf(Service Management Framework,嗯,多好的名字,在那么多的platform實現(xiàn)中,我個人最喜歡這個名字,言簡意賅)。

    德國的ProSyst公司(http://www.prosyst.com)是OSGi Alliance中非常活躍的推動者,看看他們的產(chǎn)品列表吧http://www.prosyst.com/products/osgi.html(他們甚至提供了kvm + cldc的OSGi framework)

    開源的Oscar(http://oscar.objectweb.org/),Knopflerfish(http://www.knopflerfish.org/)

    對于OSGi的成功應(yīng)用,最有名的應(yīng)該是eclipse了,它就是基于OSGi service platform的產(chǎn)品。還有Apache,據(jù)說OSGi將被應(yīng)用于其新一代的build工具中。這些都是j2se和j2ee的應(yīng)用,而基于j2me的,手機(對應(yīng)OSGi Alliance的MEG)和車載設(shè)備(對應(yīng)OSGi Alliance的VEG)是OSGi的主要領(lǐng)域,OSGi Alliance已經(jīng)有相應(yīng)的規(guī)范,這些領(lǐng)域的應(yīng)用相信會更加精彩,讓我們拭目以待吧。

    posted @ 2006-02-14 15:32 勤勞的蜜蜂 閱讀(23147) | 評論 (10)編輯 收藏

    僅列出標(biāo)題
    共2頁: 上一頁 1 2 
    主站蜘蛛池模板: 亚洲狠狠ady亚洲精品大秀| 国产一级一片免费播放| 蜜桃视频在线观看免费视频网站WWW | A片在线免费观看| 最新亚洲成av人免费看| baoyu122.永久免费视频| 热99RE久久精品这里都是精品免费| 岛国岛国免费V片在线观看| 国产三级在线免费观看| 国产又黄又爽胸又大免费视频| 中文字幕不卡高清免费| 国产羞羞的视频在线观看免费| 午夜老司机永久免费看片| 69av免费观看| 日韩av无码成人无码免费| 免费无码不卡视频在线观看 | 二区久久国产乱子伦免费精品| 成年女人A毛片免费视频| 国产成人一区二区三区视频免费| 午夜精品免费在线观看| 一二三四在线观看免费高清中文在线观看 | 美女18一级毛片免费看| 一区二区三区免费高清视频| 成人久久免费网站| 亚洲黄色免费电影| 午夜小视频免费观看| 免费a级毛片视频| 亚洲AV无码欧洲AV无码网站| 亚洲精品自在线拍| 亚洲第一成年免费网站| www在线观看播放免费视频日本| 国内精品免费视频精选在线观看| 在线a免费观看最新网站| 日本人的色道www免费一区| 精品国产亚洲一区二区在线观看 | 亚洲真人日本在线| 亚洲91av视频| 亚洲成在人线在线播放无码| 亚洲免费一区二区| 无码av免费毛片一区二区| 国产免费av片在线无码免费看 |