對osgi有了一個初步的瞭解之後,準備寫段代碼跑跑,一試身手,
先下載了一份Bluedavy 的《OSGI實戰》
裏邊有可以直接運行的代碼,雙擊run.bat運行正常,暗爽!
開始練習《OSGI實戰》中用戶登錄驗證模塊,一行一行敲代碼,第一個變化就是工程之間相互引用不能在Build path裏添加工程引用了,改成了在MANIFEST.MF當中添加Import-Package
在學習過程當中還是遇到了不少問題,記錄下來,幫助遇到和我同樣樣問題的少走彎路。
我用的是eclipse3.4 jdk1.6
1.Import-Package時org.eclipse.equinox.servlet.api這個包死活找不到。
在eclipse3.4已經不存在了直接導入javax.servlet_2.4.0.v200806031604.jar就可以了
如果沒有添加javax.servlet會出現 INSTALLED UserValidatorWebBundle_1.0.0
強行啓動會拋出以下異常
org.osgi.framework.BundleException: The bundle could not be resolved. Reason: Missing Constraint: Require-Bundle: javax.servlet; bundle-version="2.4.0"
2.如果使用了Equinox OSGI Declarative Service需要下載
eclipse-equinox-SDK-3.4.2.zip
因爲Declarative Service實現並沒有包含在Eclipse的默認軟件包中,需要單獨從 Eclipse 的的網站上獲得,下載包當中的plugins和features複製到eclipse當中重啓
org.eclipse.equinox.ds_1.0.0.v20080427-0830.jar是運行時用到的bundle
org.eclipse.equinox.ds用到了org.eclipse.equinox.util_1.0.0.v20080414.jar
都要在config.ini當中添加並啓動
3.一切看似啓動正常了,log當中還是有以下異常
java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).
還得啓動 org.eclipse.osgi.util_3.1.300.v20080303.jar 這個bundle
4.如果http://localhost/demo/page/login.htm 這個頁面不能訪問可能org.eclipse.equinox.http_1.0.200.v20080421-2006.jar沒有啓動,如何htm能訪問了http://localhost/demo/login 不能訪問 可能org.eclipse.equinox.http.servlet_1.0.100.v20080427-0830.jar沒有啓動
總結一下用戶登錄驗證模塊要啓動的bundle
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.2.R34x_v20080826-1230
1 ACTIVE ConfigFileValidatorBundle_1.0.0
2 ACTIVE DBValidatorBundle_1.0.0
4 ACTIVE UserValidatorBundle_1.0.0
5 ACTIVE LDAPValidatorBundle_1.0.0
9 ACTIVE UserValidatorWebBundle_1.0.0
10 ACTIVE org.eclipse.equinox.util_1.0.0.v20080414
11 ACTIVE org.eclipse.equinox.ds_1.0.0.v20080427-0830
12 ACTIVE javax.servlet_2.4.0.v200806031604
13 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203
14 ACTIVE org.eclipse.equinox.http.servlet_1.0.100.v20080427-0830
15 ACTIVE org.eclipse.equinox.http_1.0.200.v20080421-2006
17 ACTIVE org.eclipse.osgi.util_3.1.300.v20080303
當缺少什麼bundle時,自己去網上下就行,然後用導入Plug- ins and Fragments的方式將bundle導入,便可以引用了,所以別當成什麼高深的東西,別忘了在運行時用"Add Required Bundles",它幫我們加入會用的的bundles,這個就幫我們很大的忙了.
在第一個例子(源碼中的classic)中,用代碼註冊的方式來註冊服務,即在每個實現服務接口的bundle裏的Activator註冊自己的服務到指定服務名下,如
- package org.riawork.demo.user.validator;
- /*
- * RIAWork.org
- *
- * OSGI Opendoc Demo
- */
- import org.osgi.framework.BundleActivator;
- import org.osgi.framework.BundleContext;
- import org.osgi.framework.ServiceRegistration;
- import org.riawork.demo.service.user.Validator;
- import org.riawork.demo.service.user.impl.ConfigFileValidatorImpl;
- /**
- * desc: ConfigFileBundle Activator,採用傳統的方式完成服務的註冊
- *
- * @author jerry
- */
- public class Activator implements BundleActivator {
- // --------------------------------------------Instance Variables
- private ServiceRegistration serviceReg=null;
- // --------------------------------------------Public Method
- /* (non-Javadoc)
- * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
- */
- //實現Validator的Bunble都會在Activator裏將自己的新的實現註冊到Validator.class.getName()名下,這樣Validator.class.getName()爲名的服務就有多個了
- public void start(BundleContext context) throws Exception {
- serviceReg=context.registerService(Validator.class.getName(), new ConfigFileValidatorImpl(), null);
- }
- /* (non-Javadoc)
- * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
- */
- public void stop(BundleContext context) throws Exception {
- if(serviceReg!=null)
- serviceReg.unregister();
- }
- }
package org.riawork.demo.user.validator;
/*
* RIAWork.org
*
* OSGI Opendoc Demo
*/
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.riawork.demo.service.user.Validator;
import org.riawork.demo.service.user.impl.ConfigFileValidatorImpl;
/**
* desc: ConfigFileBundle Activator,採用傳統的方式完成服務的註冊
*
* @author jerry
*/
public class Activator implements BundleActivator {
// --------------------------------------------Instance Variables
private ServiceRegistration serviceReg=null;
// --------------------------------------------Public Method
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
//實現Validator的Bunble都會在Activator裏將自己的新的實現註冊到Validator.class.getName()名下,這樣Validator.class.getName()爲名的服務就有多個了
public void start(BundleContext context) throws Exception {
serviceReg=context.registerService(Validator.class.getName(), new ConfigFileValidatorImpl(), null);
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
if(serviceReg!=null)
serviceReg.unregister();
}
}
在第二個例子(源碼中的ds),採用的是在配置文件裏聲明的方式來發佈一個bundle裏的服務的,即在 ConfigFileValidatorBundle,DBValidatorBundle,LDAPValidatorBundle這三個實現 UserValidatorBundle接口的bundle裏沒有Activator來註冊它們的實現服務,而是在MANIFEST.MF配置文件里加入 Service-Component: OSGI-INF/component.xml來發布聲明在項目目錄下的OSGI-INF/component.xml配置文件的服務。
打包時,按着文檔來做是不行的,打包的時候,org.eclipse.osgi的jar包和run.bat是在一個目錄裏,而在它們目錄下再建 configuration目錄(存放config.ini文件)和bundles目錄(存放自己打包出來的bundle和它們運行依賴的 bundle),還有一點在注意的是拷貝文檔裏的config.ini內容到config.ini文件是不能運行的,可以是有中文字符在裏面。
我這裏能運行的如下:
- osgi.noShutdown=true
- # 當前系統下運行的 Bundle,可以在此指定 Bundle 的啓動順序,在後續的
- # StartLevel Service章節中會詳細的介紹
- #避免Unable to acquire application service. Ensure that the org.eclipse.core.runtime錯誤
- eclipse.ignoreApp=true
- #osgi.bundles=reference\:file\:bundles/ConfigFileValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/DBValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/LDAPValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/org.eclipse.equinox.http_1.0.301.R35x_v20090728.jar@start,reference\:file\:bundles/javax.servlet_2.5.0.v200806031605.jar@start,reference\:file\:bundles/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,reference\:file\:bundles/UserValidatorBundle_1.0.0.jar@start, reference\:file\:bundles/UserValidatorWebBundle_1.0.0.jar@start
- osgi.bundles=plugins/ConfigFileValidatorBundle_1.0.0.jar@start,\
- plugins/DBValidatorBundle_1.0.0.jar@start,\
- plugins/LDAPValidatorBundle_1.0.0.jar@start,\
- plugins/org.eclipse.equinox.http_1.0.301.R35x_v20090728.jar@start,\
- plugins/javax.servlet_2.5.0.v200806031605.jar@start,\
- plugins/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,\
- plugins/UserValidatorBundle_1.0.0.jar@start,\
- plugins/UserValidatorWebBundle_1.0.0.jar@start,\
- plugins/org.eclipse.equinox.ds_1.1.1.R35x_v20090806.jar@start,\
- plugins/org.eclipse.equinox.util_1.0.100.v20090520-1800.jar@start
- osgi.bundles.defaultStartLevel=4
osgi.noShutdown=true # 當前系統下運行的 Bundle,可以在此指定 Bundle 的啓動順序,在後續的 # StartLevel Service章節中會詳細的介紹 #避免Unable to acquire application service. Ensure that the org.eclipse.core.runtime錯誤 eclipse.ignoreApp=true #osgi.bundles=reference\:file\:bundles/ConfigFileValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/DBValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/LDAPValidatorBundle_1.0.0.jar@start,reference\:file\:bundles/org.eclipse.equinox.http_1.0.301.R35x_v20090728.jar@start,reference\:file\:bundles/javax.servlet_2.5.0.v200806031605.jar@start,reference\:file\:bundles/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,reference\:file\:bundles/UserValidatorBundle_1.0.0.jar@start, reference\:file\:bundles/UserValidatorWebBundle_1.0.0.jar@start osgi.bundles=plugins/ConfigFileValidatorBundle_1.0.0.jar@start,\ plugins/DBValidatorBundle_1.0.0.jar@start,\ plugins/LDAPValidatorBundle_1.0.0.jar@start,\ plugins/org.eclipse.equinox.http_1.0.301.R35x_v20090728.jar@start,\ plugins/javax.servlet_2.5.0.v200806031605.jar@start,\ plugins/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,\ plugins/UserValidatorBundle_1.0.0.jar@start,\ plugins/UserValidatorWebBundle_1.0.0.jar@start,\ plugins/org.eclipse.equinox.ds_1.1.1.R35x_v20090806.jar@start,\ plugins/org.eclipse.equinox.util_1.0.100.v20090520-1800.jar@start osgi.bundles.defaultStartLevel=4
這裏不要忘記加入ds的bundle不然用Service-Component: OSGI-INF/component.xml配置就不起作用了,發佈不了服務的,因爲是由ds的bundle來掃描發現相應的服務,並加於管理的。