java bundle id_OSGi介绍(五)两个bundle

(四)中提到的直接型改造法实际上和一个传统的java应用程序没有区别。因此客户的需求发生变化,通常是牵一发而动全身。

那么我们现在就看看如果在osgi framework中,用多个bundle来实现的效果吧。

我的想法是用两个bundle来配合实现“扶贫助手”的功能。一个bundle专门负责录入和显示纪录,一个bundle专门负责纪录的数据结构和对数据的处理,用时下时髦的说法就是使用了mvc,只是我的m和c放到了一起。

先看看mc的bundle实现代码片断:

4f1150b881333f12a311ae9ef34da474.pngpackagecom.wukong.test.family.control;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.*;

4f1150b881333f12a311ae9ef34da474.pngimportcom.wukong.test.family.control.impl.*;

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicinterfaceFamilyInfoDatabase9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicstaticclassFamilyFactory9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivatestaticFamilyInfoDatabase database;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicstaticFamilyInfoDatabase getDatabaseInstance()9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(database==null)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                database=newFamilyDatabase();

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngreturndatabase;

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.pngpublicString[] getColumns();

d18c02628675d0a2c816449d98bda930.pngpublicObject getValueAt(introw,intcolumn);

d18c02628675d0a2c816449d98bda930.pngpublicString[] getSortingFields();

d18c02628675d0a2c816449d98bda930.pngpublicintgetRowCount();

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngpublicvoidsort(String sortField)throwsIllegalArgumentException;

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngpublicvoidaddEntry(List columns, List values)throwsIllegalArgumentException;

d18c02628675d0a2c816449d98bda930.pngpublicvoiddeleteEntry(String familyName);

d18c02628675d0a2c816449d98bda930.pngpublicvoidupdate(String familyName,List columns, List values)throwsIllegalArgumentException;

8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

这个interface是用来描述一个数据库所具备的基本功能。注意,这个interface被放到了package com.wukong.test.family.control中。

另外,这个interface还提供了一个内嵌类,用来专门提供一个工厂方法来产生唯一的一个数据库实例。

对于这个数据库的实现,代码片断如下(增加,删除和修改的代码都被省略了,只给出排序的代码):

4f1150b881333f12a311ae9ef34da474.pngpackagecom.wukong.test.family.model.impl;

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassFamilyInfoEntry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateString familyName;

d18c02628675d0a2c816449d98bda930.pngprivateintpopulation;

d18c02628675d0a2c816449d98bda930.pngprivateintincomePerYear;

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif    FamilyInfoEntry(String familyName,intpopulation,intincome)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.familyName=familyName;

d18c02628675d0a2c816449d98bda930.pngthis.population=population;

d18c02628675d0a2c816449d98bda930.pngthis.incomePerYear=income;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif    String getFamilyName()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnfamilyName;

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifintgetIncomePerYear()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnincomePerYear;

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifintgetPopulation()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnpopulation;

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.wukong.test.family.control.impl;

4f1150b881333f12a311ae9ef34da474.pngimportcom.wukong.test.family.control.FamilyInfoDatabase;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.*;

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassFamilyDatabaseimplementsFamilyInfoDatabase9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateLinkedList familyEntryList=newLinkedList();

d18c02628675d0a2c816449d98bda930.pngprivateObject[] sortedValues=null;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicFamilyDatabase()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Zhang",3,1200));

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Li",6,1800));

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Liu",4,1500));

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicString[] getColumns()9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifreturnnewString[]9b8a8a44dd1c74ae49c20a7cd451974e.png{"Family Name","Family Population","Income"};

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicObject getValueAt(introw,intcolumn)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        FamilyInfoEntry entry=(FamilyInfoEntry)this.sortedValues[row];

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifswitch(column)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngcase0:

d18c02628675d0a2c816449d98bda930.pngreturnentry.getFamilyName();

d18c02628675d0a2c816449d98bda930.pngcase1:

d18c02628675d0a2c816449d98bda930.pngreturnnewInteger(entry.getPopulation());

d18c02628675d0a2c816449d98bda930.pngcase2:

d18c02628675d0a2c816449d98bda930.pngreturnnewInteger(entry.getIncomePerYear());

d18c02628675d0a2c816449d98bda930.pngdefault:

d18c02628675d0a2c816449d98bda930.pngthrownewIllegalArgumentException("Invalid column index.");

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicString[] getSortingFields()9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifreturnnewString[]9b8a8a44dd1c74ae49c20a7cd451974e.png{"FamilyName","Income"};

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintgetRowCount()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnthis.familyEntryList.size();

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.pngpublicvoidaddEntry(List columns, List values)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifthrowsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoiddeleteEntry(String familyName)9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.pngpublicvoidupdate(String familyName, List columns, List values)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifthrowsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidsort(String sortField)throwsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(sortField.equals("FamilyName"))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

d18c02628675d0a2c816449d98bda930.png            Arrays.sort(this.sortedValues,newSortedByName());

d18c02628675d0a2c816449d98bda930.png            

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(sortField.equals("Income"))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

d18c02628675d0a2c816449d98bda930.png            Arrays.sort(this.sortedValues,newSortedByIncome());

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngthrownewIllegalArgumentException("Sorting enties by field '"+sortField+"' is not supported."); 

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassSortedByNameimplementsComparator9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintcompare(Object entry1,Object entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(entry1==entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn0;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en1=(FamilyInfoEntry) entry1;

d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en2=(FamilyInfoEntry) entry2;

d18c02628675d0a2c816449d98bda930.png            

d18c02628675d0a2c816449d98bda930.pngreturnen1.getFamilyName().compareTo(en2.getFamilyName());

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png        

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassSortedByIncomeimplementsComparator9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintcompare(Object entry1, Object entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(entry1==entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn0;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en1=(FamilyInfoEntry) entry1;

d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en2=(FamilyInfoEntry) entry2;

d18c02628675d0a2c816449d98bda930.pngreturnen1.getIncomePerYear()-en2.getIncomePerYear();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

同样需要注意的是我们把这个实现放到了package com.wukong.test.family.control.impl中

下面看看v的bundle实现。

4f1150b881333f12a311ae9ef34da474.pngpackagecom.wukong.test.family.gui;

4f1150b881333f12a311ae9ef34da474.pngimportorg.osgi.framework.*;

4f1150b881333f12a311ae9ef34da474.pngimportjavax.swing.*;

4f1150b881333f12a311ae9ef34da474.pngimportjavax.swing.table.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.awt.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.awt.event.*;

4f1150b881333f12a311ae9ef34da474.pngimportcom.wukong.test.family.control.*;

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassFamilyInfoGuiimplementsBundleActivator, ActionListener,ItemListener9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateJFrame mainFrame;

d18c02628675d0a2c816449d98bda930.pngprivateJPanel contentPanel;

d18c02628675d0a2c816449d98bda930.pngprivateJTable familiesTable;

d18c02628675d0a2c816449d98bda930.pngprivateJScrollPane familiesTableScrollPane;

d18c02628675d0a2c816449d98bda930.pngprivateJPanel sortedByPanel=newJPanel(newGridLayout(1,2));

d18c02628675d0a2c816449d98bda930.pngprivateJLabel sortedByLabel=newJLabel("Sorted By:");

d18c02628675d0a2c816449d98bda930.pngprivateJComboBox sortedByList=null;

d18c02628675d0a2c816449d98bda930.pngprivateJPanel commandPanel=newJPanel(newGridLayout(1,3));

d18c02628675d0a2c816449d98bda930.pngprivateJButton addEntry=newJButton("Add");

d18c02628675d0a2c816449d98bda930.pngprivateJButton deleteEntry=newJButton("Delete");

d18c02628675d0a2c816449d98bda930.pngprivateJButton updateEntry=newJButton("Update");

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.png    FamilyInfoDatabase database=null;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidstart(BundleContext context)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif        Runnable r=newRunnable()9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidrun()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                contentPanel=newJPanel();

d18c02628675d0a2c816449d98bda930.png                familiesTableScrollPane=newJScrollPane();

d18c02628675d0a2c816449d98bda930.png                database=FamilyInfoDatabase.FamilyFactory

d18c02628675d0a2c816449d98bda930.png                        .getDatabaseInstance();

d18c02628675d0a2c816449d98bda930.png                familiesTable=newJTable(newFamilyInfoTableModel(database));

d18c02628675d0a2c816449d98bda930.png                familiesTableScrollPane.setViewportView(familiesTable);

d18c02628675d0a2c816449d98bda930.png                

d18c02628675d0a2c816449d98bda930.png                String[] sortedFields=database.getSortingFields();

d18c02628675d0a2c816449d98bda930.png                

d18c02628675d0a2c816449d98bda930.png                sortedByList=newJComboBox(sortedFields);

d18c02628675d0a2c816449d98bda930.png                

d18c02628675d0a2c816449d98bda930.png                sortedByList.addItemListener(FamilyInfoGui.this);

d18c02628675d0a2c816449d98bda930.png                sortedByPanel.add(sortedByLabel);

d18c02628675d0a2c816449d98bda930.png                sortedByPanel.add(sortedByList);

d18c02628675d0a2c816449d98bda930.png                commandPanel.add(addEntry);

d18c02628675d0a2c816449d98bda930.png                commandPanel.add(deleteEntry);

d18c02628675d0a2c816449d98bda930.png                commandPanel.add(updateEntry);

d18c02628675d0a2c816449d98bda930.png                contentPanel.add(sortedByPanel, BorderLayout.NORTH);

d18c02628675d0a2c816449d98bda930.png                contentPanel.add(familiesTableScrollPane, BorderLayout.CENTER);

d18c02628675d0a2c816449d98bda930.png                contentPanel.add(commandPanel, BorderLayout.SOUTH);

d18c02628675d0a2c816449d98bda930.png                mainFrame=newJFrame();

d18c02628675d0a2c816449d98bda930.png                mainFrame.setContentPane(contentPanel);

d18c02628675d0a2c816449d98bda930.png                mainFrame.setSize(newDimension(500,600));

d18c02628675d0a2c816449d98bda930.png                mainFrame.show();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        };

d18c02628675d0a2c816449d98bda930.png        Thread t=newThread(r);

d18c02628675d0a2c816449d98bda930.png        t.start();

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidstop(BundleContext context)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.mainFrame.dispose();

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidactionPerformed(ActionEvent event)9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoiditemStateChanged(ItemEvent event)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(event.getSource()==this.sortedByList)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            String sortingField=(String)event.getItem();

d18c02628675d0a2c816449d98bda930.pngthis.database.sort(sortingField);

d18c02628675d0a2c816449d98bda930.pngthis.familiesTable.repaint();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassFamilyInfoTableModelextendsAbstractTableModel9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateFamilyInfoDatabase database;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif        FamilyInfoTableModel(FamilyInfoDatabase database)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.database=database;

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicString getColumnName(intcol)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturndatabase.getColumns()[col];

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicbooleanisCellEditable(introw,intcol)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnfalse;

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintgetColumnCount()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturndatabase.getColumns().length;

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintgetRowCount()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturndatabase.getRowCount();

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicObject getValueAt(introw,intcol)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturndatabase.getValueAt(row, col);

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}

v的实现基本是界面的构造,而关于数据库,它只能看到interface FamilyInfoDatabase,因为它只import com.wukong.test.family.control.*,然后通过FamilyInfoDatabase内嵌静态类的静态工厂方法获得数据库的实例,这样它完全不用关心数据库如何实现。

源码编译后得到class文件后,下一步我们的工作就要来构造这两个bundle。最关键的步骤就是为每个bundle写它的manifest文件

我们先给出mc bundle的manifest文件(familycontrol.mf):

4f1150b881333f12a311ae9ef34da474.pngManifest-Version:1.04f1150b881333f12a311ae9ef34da474.pngBundle-SymbolicName: com.wukong.test.family.control

4f1150b881333f12a311ae9ef34da474.pngBundle-Name: family control

4f1150b881333f12a311ae9ef34da474.pngBundle-Version:1.04f1150b881333f12a311ae9ef34da474.pngBundle-Vendor: LiMing

4f1150b881333f12a311ae9ef34da474.pngExport-Package: com.wukong.test.family.control

4f1150b881333f12a311ae9ef34da474.png

非常简单,但请大家注意这行

Export-Package: com.wukong.test.family.control

它告诉framework,这个bundle提供com.wukong.test.family.control这个包。

所谓“bundle A提供某个包”意思,通俗简单的理解是如果bundle B在manifest文件中说明要使用这个包(通过Import-Package这个关键字,下面会在v bundle中有说明)那么bundle B运行时,当使用到这个包中的类时,framework将告诉B的class loader这个类的定义是来自bundle A,从而不会发生ClassNotFoundException。另外值得一提的是我们并没有把com.wukong.test.family.control.impl这个包加进来,这样做的目的也是为了隐藏具体实现。将来只要interface不变,我们可以使用不同的实现来替换现有实现,大大提高扩展性。

还有一点,细心的话,你会发现这个bundle没有activator。这是允许的,这种bundle就像动态连接库,只提供接口和方法以及实现,等待其他实体的调用,而本身不能运行。

再来看看v bundle的manifest文件(family.mf):

4f1150b881333f12a311ae9ef34da474.pngManifest-Version:1.04f1150b881333f12a311ae9ef34da474.pngBundle-SymbolicName: com.wukong.test.family.gui

4f1150b881333f12a311ae9ef34da474.pngBundle-Name: family gui

4f1150b881333f12a311ae9ef34da474.pngBundle-Version:1.04f1150b881333f12a311ae9ef34da474.pngBundle-Vendor: LiMing

4f1150b881333f12a311ae9ef34da474.pngBundle-Activator: com.wukong.test.family.gui.FamilyInfoGui

4f1150b881333f12a311ae9ef34da474.pngImport-Package: org.osgi.framework;version=1.3,com.wukong.test.family.control4f1150b881333f12a311ae9ef34da474.png

正如上面曾经提到过的一样,我们在Import-Package:关键字中指定该bundle需要使用com.wukong.test.family.control包。在v bundle的源代码中,我们也看到这个bundle的确使用了com.wukong.test.family.control包中的FamilyInfoDatabase。更深入一点,我们可以简单的这样理解,当v bundle运行的时候,framework通过匹配bundle间的Import-Package和Export-Package,

然后告诉v bundle,FamilyInfoDatabase这个类型的定义和装载实际上是由mc bundle完成的。这样,v bundle就会使用mc bundle的class loader来加在这个类型。另外,按照osgi framework的spec规定,javax.swing;javax.swing.table;java.awt;java.awt.event这4个包都都不属于framework的必备包,所以应该在Import-Package中指定。为了不用在Import-Package中指定这4个包,这个例子要求运行在sun的j2se的jvm(比如version 1.4.2_04),这样4个包都作为java api由bootstrap classloader加载,每个bundle都可以直接使用了。

有了manifest文件,我们最后就是打jar包了。

比如在windows下,你把两个manifest文件放在包的根目录,然后执行以下命令

jar -cvfm family.jar family.mf com\wukong\test\family\gui\*.class

jar -cvfm familycontrol.jar familycontrol.mf com\wukong\test\family\control

这样,我们就可以认为family.jar是我们的v bundle而familycontrol.jar是我们的mc bundle。

下面,我们就来安装运行这两个bundle吧。

我将首先简单介绍一个我自己编写的osgi framework,然后结合这个demo framework来部署和运行新的“扶贫助手”。

本人编写的osgi framework基本上完成了spec r4的核心规范,但是与安全相关的功能都没有实现。

启动这个framework后,它的shell提供了如下简单的framework管理功能命令:

bl 即bundle list,查看所有已经安装的bundle

dl 即detailed bundle list,用来查看某个bundle的详细信息

sl 即service list,用来查看所有已经注册的service

ls 即list setting,用来查看所有设置的系统属性(System.getProperties)和framework当前的active start level

in 即install bundle,通过指定bundle文件的url来安装该bundle

up 即update bundle,通过指定bundle id来升级指定的bundle

un 即uninstall bundle,通过指定bundle id来卸载指定的bundle

stt 即start bundle,通过指定bundle id来启动指定的bundle

stp 即stop bundle,通过指定bundle id来停止指定bundle的运行

rst 即restart bundle,通过指定bundle id来重新启动指定的bundle

rfr 即refresh package,当某些bundle被更新或卸载后,如果不执行这个命令,那么被更新或卸载的bundle的Export-Package(如果有的话)将继续服役,

也就是说,之前使用这些包的bundle不会因为这个bundle被更新或者卸载而发生变化。而执行这个命令后,受影响的bundle将被重新解析

rest 即restart,重新启动framework,属于“热起”

shut 即shutdown,停止整个framework的运行

set 用来设置framework的active startlevel或者某个bundle的start level

log 用来查看系统的日志信息

现在我们来假设运行环境如下:

OS: window

jvm: j2se 1.4.2_04

family.jar和familycontrol.jar这两个文件放在D:/framework/bundles目录下

第一步:安装bundle

输入以下两条命令:

in file:D:/framework/bundles/familycontrol.jar

in file:D:/framework/bundles/family.jar

然后用bl命令查看结果,其中得到如下显示结果:

Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name

0  OSGiFramework Active  0  System Bundle     system.bundle

.

.(省略部分结果显示)

.

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

说明两个bundle安装成功,其中mc bundle的id是16, v bundle的id是17

第二步:启动bundle

可以输入以下命令

stt 16,17

然后我们就可以看到一个JFrame显示出来,里面显示了3条记录,没有任何顺序(其顺序实际上是在程序中添加到LinkedList的顺序)。我们可以在Sorted By的列表中看到有两个选择“FamilyName”和“Income”,当选择“Income”时,你将发现3条记录按年收入由小到大排列起来。程序的运行完全符合我们的意图。

这时如果我们再用bl命令查看,将得到如下结果:

Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name

0  OSGiFramework Active  0  System Bundle     system.bundle

.

.(省略部分结果显示)

.

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没有Activator,所以启动这个bundle只会使其进入Resolved状态。

有了这样的结构,程序变得灵活些了。现在假设客户提出需要增加一个字段,即人均年收入,并且提供按人均年收入排列纪录。看看framework框架下,这样的变动是如何的简单!

首先,我们通过分析,发现只要更改mc bundle的代码,使得数据库的实现中增加这个字段以及相应的排序方法即可。更新后的代码如下:

4f1150b881333f12a311ae9ef34da474.pngpackagecom.wukong.test.family.control.impl;

4f1150b881333f12a311ae9ef34da474.pngimportcom.wukong.test.family.control.FamilyInfoDatabase;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.*;

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassFamilyDatabaseimplementsFamilyInfoDatabase9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateLinkedList familyEntryList=newLinkedList();

d18c02628675d0a2c816449d98bda930.pngprivateObject[] sortedValues=null;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicFamilyDatabase()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Zhang",3,1260));

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Li",6,1800));

d18c02628675d0a2c816449d98bda930.pngthis.familyEntryList.add(newFamilyInfoEntry("Liu",4,1500));

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicString[] getColumns()9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifreturnnewString[]9b8a8a44dd1c74ae49c20a7cd451974e.png{"Family Name","Family Population","Income","IncomePerPerson"};//添加了“IncomePerPerson”字段ecedf933ec37d714bd4c2545da43add2.png}97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicObject getValueAt(introw,intcolumn)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        FamilyInfoEntry entry=(FamilyInfoEntry)this.sortedValues[row];

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifswitch(column)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngcase0:

d18c02628675d0a2c816449d98bda930.pngreturnentry.getFamilyName();

d18c02628675d0a2c816449d98bda930.pngcase1:

d18c02628675d0a2c816449d98bda930.pngreturnnewInteger(entry.getPopulation());

d18c02628675d0a2c816449d98bda930.pngcase2:

d18c02628675d0a2c816449d98bda930.pngreturnnewInteger(entry.getIncomePerYear());

d18c02628675d0a2c816449d98bda930.pngcase3:

d18c02628675d0a2c816449d98bda930.pngreturnnewInteger(entry.getIncomePerYear()/entry.getPopulation());//计算人均年收入d18c02628675d0a2c816449d98bda930.pngdefault:

d18c02628675d0a2c816449d98bda930.pngthrownewIllegalArgumentException("Invalid column index.");

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicString[] getSortingFields()9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png    }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintgetRowCount()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnthis.familyEntryList.size();

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.pngpublicvoidaddEntry(List columns, List values)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifthrowsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//TODO Auto-generated method stubecedf933ec37d714bd4c2545da43add2.png}97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoiddeleteEntry(String familyName)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//TODO Auto-generated method stubecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngpublicvoidupdate(String familyName, List columns, List values)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifthrowsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//TODO Auto-generated method stubecedf933ec37d714bd4c2545da43add2.png}97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidsort(String sortField)throwsIllegalArgumentException9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(sortField.equals("FamilyName"))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

d18c02628675d0a2c816449d98bda930.png            Arrays.sort(this.sortedValues,newSortedByName());

d18c02628675d0a2c816449d98bda930.png            

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(sortField.equals("Income"))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

d18c02628675d0a2c816449d98bda930.png            Arrays.sort(this.sortedValues,newSortedByIncome());

ecedf933ec37d714bd4c2545da43add2.png        }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(sortField.equals("IncomePerPerson"))9b8a8a44dd1c74ae49c20a7cd451974e.png{//对纪录按人均年收入进行排序d18c02628675d0a2c816449d98bda930.pngthis.sortedValues=this.familyEntryList.toArray();

d18c02628675d0a2c816449d98bda930.png            Arrays.sort(this.sortedValues,newSortedByIPP());

d18c02628675d0a2c816449d98bda930.png            

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassSortedByNameimplementsComparator9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintcompare(Object entry1,Object entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(entry1==entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn0;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en1=(FamilyInfoEntry) entry1;

d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en2=(FamilyInfoEntry) entry2;

d18c02628675d0a2c816449d98bda930.png            

d18c02628675d0a2c816449d98bda930.pngreturnen1.getFamilyName().compareTo(en2.getFamilyName());

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png        

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassSortedByIncomeimplementsComparator9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintcompare(Object entry1, Object entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(entry1==entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn0;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en1=(FamilyInfoEntry) entry1;

d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en2=(FamilyInfoEntry) entry2;

d18c02628675d0a2c816449d98bda930.pngreturnen1.getIncomePerYear()-en2.getIncomePerYear();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifclassSortedByIPPimplementsComparator9b8a8a44dd1c74ae49c20a7cd451974e.png{//人均年收入的排序标准。97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicintcompare(Object entry1, Object entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(entry1==entry2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn0;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en1=(FamilyInfoEntry) entry1;

d18c02628675d0a2c816449d98bda930.png            FamilyInfoEntry en2=(FamilyInfoEntry) entry2;

d18c02628675d0a2c816449d98bda930.pngreturn(en1.getIncomePerYear()/en1.getPopulation())-(en2.getIncomePerYear()/en2.getPopulation());

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png        

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

编译完毕后,我们把mc bundle的manifest文件改为如下:

4f1150b881333f12a311ae9ef34da474.pngManifest-Version:1.04f1150b881333f12a311ae9ef34da474.pngBundle-SymbolicName: com.wukong.test.family.control

4f1150b881333f12a311ae9ef34da474.pngBundle-Name: family control

4f1150b881333f12a311ae9ef34da474.pngBundle-Version:2.0//由1.0改为2.04f1150b881333f12a311ae9ef34da474.pngBundle-Vendor: LiMing

4f1150b881333f12a311ae9ef34da474.pngExport-Package: com.wukong.test.family.control

4f1150b881333f12a311ae9ef34da474.png

然后使用jar工具打包,并把产生的新的familycontrol.jar依旧放在D:/framework/bundles目录下。

这时,我们只要执行下面的命令,framework就完成对mc bundle的升级工作:

up 16升级完毕后,你会发现v bundle的显示依旧没有任何变化。这时我们需要执行一个refresh package命令,来更新bundle的解析:

rfr这时,你会发现原来的JFrame被关闭了,然后又一个JFrame显示出来,里面的纪录多了一列“IncomePerPerson”,而且在“Sorted By”里面也

多了“IncomePerPerson”,而且,排序的结果也很正确。

瞧,framework为应用程序提供了强大的动态更新功能,非常方便。甚至都不用重新启动framework,更不用说JVM了。您也许会说,最终用户根本不可能帮你输入这些什么in,up晦涩的命令。还有,让用户拷贝新版本到本地似乎也不是什么好主意。嗯,这个问题说得很对。其实我是偷懒了,这些操作framework都留有接口,我们只要再编写一个专门管理这两个bundle升级的第三个bundle就可以了,这个bundle将提供友好的界面来告诉最终用户如何升级。这样就能够提供比较好的解决方案了。至于第二个问题,别忘了bundle的location是一个url,只要jvm注册了相应的url handler完全可以支持http,ftp等丰富的url,例如,升级的时候,framework自动连接到供应商的http下载服务器获取最新版本进行更新,当然,我们也可以把更强大更灵活的升级功能及选项加入到上面提到的第三个bundle中,从而极大提高了程序的易用性,而且极大降低了软件提供商的维护成本。

到此为止,我已经想不出再多好话了,但是,还可以更好!下一节,将采用service的方式来实现,嘿嘿,情况又会不一样了,到时候我会对比一下这两种实现方式的优劣。

题外话:抱歉没有拿某个著名的产品或者open source的产品来举例,我打算把自己的实现也opensource,有兴趣参与吗?不管怎样,过两天就把实现上传上来,欢迎拍砖。

posted on 2006-02-14 16:02 勤劳的蜜蜂 阅读(4288) 评论(3)  编辑  收藏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值