对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注册自己的服务到指定服务名下,如

Java代码
  1. package org.riawork.demo.user.validator;  
  2. /* 
  3.  * RIAWork.org 
  4.  *  
  5.  * OSGI Opendoc Demo 
  6.  */  
  7. import org.osgi.framework.BundleActivator;  
  8. import org.osgi.framework.BundleContext;  
  9. import org.osgi.framework.ServiceRegistration;  
  10. import org.riawork.demo.service.user.Validator;  
  11. import org.riawork.demo.service.user.impl.ConfigFileValidatorImpl;  
  12. /** 
  13.  * desc: ConfigFileBundle Activator,采用传统的方式完成服务的注册 
  14.  * 
  15.  * @author jerry 
  16.  */  
  17. public class Activator implements BundleActivator {  
  18.   
  19.     // --------------------------------------------Instance Variables  
  20.       
  21.     private ServiceRegistration serviceReg=null;  
  22.       
  23.     // --------------------------------------------Public Method  
  24.       
  25.     /* (non-Javadoc) 
  26.      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) 
  27.      */  
  28.     //实现Validator的Bunble都会在Activator里将自己的新的实现注册到Validator.class.getName()名下,这样Validator.class.getName()为名的服务就有多个了  
  29.     public void start(BundleContext context) throws Exception {  
  30.         serviceReg=context.registerService(Validator.class.getName(), new ConfigFileValidatorImpl(), null);  
  31.     }  
  32.   
  33.     /* (non-Javadoc) 
  34.      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) 
  35.      */  
  36.     public void stop(BundleContext context) throws Exception {  
  37.         if(serviceReg!=null)  
  38.             serviceReg.unregister();  
  39.     }  
  40.   
  41. }  
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文件是不能运行的,可以是有中文字符在里面。

我这里能运行的如下:

Xml代码
  1. osgi.noShutdown=true  
  2. # 当前系统下运行的 Bundle,可以在此指定 Bundle 的启动顺序,在后续的  
  3. # StartLevel Service章节中会详细的介绍  
  4. #避免Unable to acquire application service. Ensure that the org.eclipse.core.runtime错误  
  5. eclipse.ignoreApp=true  
  6.   
  7. #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  
  8. osgi.bundles=plugins/ConfigFileValidatorBundle_1.0.0.jar@start,\  
  9.           plugins/DBValidatorBundle_1.0.0.jar@start,\  
  10.         plugins/LDAPValidatorBundle_1.0.0.jar@start,\  
  11.         plugins/org.eclipse.equinox.http_1.0.301.R35x_v20090728.jar@start,\  
  12.         plugins/javax.servlet_2.5.0.v200806031605.jar@start,\  
  13.         plugins/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,\  
  14.         plugins/UserValidatorBundle_1.0.0.jar@start,\  
  15.         plugins/UserValidatorWebBundle_1.0.0.jar@start,\  
  16.         plugins/org.eclipse.equinox.ds_1.1.1.R35x_v20090806.jar@start,\  
  17.         plugins/org.eclipse.equinox.util_1.0.100.v20090520-1800.jar@start  
  18.   
  19.   
  20. 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来扫描发现相应的服务,并加于管理的。