4.测试
通过以上的实现,我们将OSGi平台集成到了Tomcat中,并且明确了web应用如何使用OSGi服务。下面就来创建一个测试的例子,看看OSGi编程模式对web应用开发的影响,同时也测试一下集成的效果。
4.1 创建并发布OSGi服务
Step1.创建插件工程com.dinstone.demo.user,选择standard OSGi framework。创建接口:
package com.dinstone.demo.user;
publicinterface IUserService { public String getUserName(String id); } |
Step2.创建插件工程com.dinstone.demo.user.db,创建类UserServiceImpl实现IUserService接口。
package com.dinstone.demo.user.db; imp<wbr>ort java.util.logging.Logger;</wbr> imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceImpl implements IUserService {
private static Logger log = Logger.getLogger(UserServiceImpl.class .getName());
@Override public String getUserName(String id) { log.info("get user name from db"); return "db" + id; } } |
Step3.向OSGi平台发布IUserService服务。创建Activator注册服务对象。
package com.dinstone.demo.user.db;
imp<wbr>ort java.util.Properties;</wbr>
imp<wbr>ort org.osgi.framework.BundleActivator;</wbr> imp<wbr>ort org.osgi.framework.BundleContext;</wbr> imp<wbr>ort org.osgi.framework.ServiceRegistration;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class Activator implements BundleActivator {
private ServiceRegistration serviceReg;
/* * (non-Javadoc) * * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(BundleContext context) throws Exception { Properties p = new Properties(); serviceReg = context.registerService(IUserService.class.getName(), new UserServiceImpl(), p); }
/* * (non-Javadoc) * * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { serviceReg.unregister(); }
} |
Step4. 创建插件工程com.dinstone.demo.user.file,创建类UserServiceImpl实现IUserService接口。
package com.dinstone.demo.user.file;
imp<wbr>ort java.util.logging.Logger;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceImpl implements IUserService {
private static Logger log = Logger.getLogger(UserServiceImpl.class .getName());
@Override public String getUserName(String id) { log.info("get user name from file"); return "file" + id; } } |
Step5.向OSGi平台发布IUserService服务。创建Activator注册服务对象。
package com.dinstone.demo.user.file;
imp<wbr>ort java.util.Properties;</wbr>
imp<wbr>ort org.osgi.framework.BundleActivator;</wbr> imp<wbr>ort org.osgi.framework.BundleContext;</wbr> imp<wbr>ort org.osgi.framework.ServiceRegistration;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class Activator implements BundleActivator {
private ServiceRegistration serviceReg;
/* * (non-Javadoc) * * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(BundleContext context) throws Exception { Properties p = new Properties(); serviceReg = context.registerService(IUserService.class.getName(), new UserServiceImpl(), p); }
/* * (non-Javadoc) * * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { serviceReg.unregister(); } } |
4.2 创建Web应用
Step1.创建动态web工程webDemo,并新建类:UserServiceFacade。
package com.dinsotne.web.demo;
imp<wbr>ort com.dinsotne.web.osgi.OsgiServiceFacade;</wbr> imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceFacade {
public static String getUserName(String id) { try { IUserService service = OsgiServiceFacade.getOsgiService( "osgi/services", IUserService.class, IUserService.class .getName());
return service.getUserName(id); } catch (IllegalArgumentException e) { e.printStackTrace(); e.printStackTrace(); }
return null; } } |
Step2.创建index.jsp页面。
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@page imp<wbr>ort</wbr>="com.dinsotne.web.demo.UserServiceFacade"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> </head> <body> User Name is <%=UserServiceFacade.getUserName("001") %>
</body> </html> |
Step3.修改web.xml文件,添加红色部分。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>webDemo</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <resource-env-ref> <description>osgi service</description> <resource-env-ref-name>osgi/services</resource-env-ref-name> <resource-env-ref-type> com.dinstone.osgi.OsgiServices </resource-env-ref-type> </resource-env-ref> </web-app> |
说明:
1. 由于UserServiceFacade依赖IUserService类,故需要将com.dinstone.demo.user_1.0.0.jar(参见4.3)添加到lib中。
2. 由于UserServiceFacade依赖OsgiServiceFacade类,故将com.dinsotne.web.osgi_1.12.0.jar(参见3.4说明)添加到lib中。
4.3 发布OSGi Bundle
Step1.依次从插件工程导出插件包:com.dinstone.demo.user_1.0.0.jar,com.dinstone.demo.user.file_1.0.0.jar,com.dinstone.demo.user.db_1.0.0.jar。
Step2.将以上的插件放于${Tomcat_Home}\osgi\felix\bundle目录下。
4.4 发布web应用
Step1.导出web应用webDemo.war。
Step2.将webDemo.war放于${Tomcat_Home}\webapps目录下。
4.5 启动Tomcat并安装OSGi Bundle
Step1.在命令行下启动Tomcat。E:\Cluster\apache-tomcat-6.0.18为我的${Tomcat_Home}。
E:\Cluster\apache-tomcat-6.0.18>bin\startup.bat Using CATALINA_BASE: E:\Cluster\apache-tomcat-6.0.18 Using CATALINA_HOME: E:\Cluster\apache-tomcat-6.0.18 Using CATALINA_TMPDIR: E:\Cluster\apache-tomcat-6.0.18\temp Using JRE_HOME: C:\Program Files\Java\jdk1.6.0_10 2009-8-12 13:21:39 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent 信息: The osgi content is initialized. Using osgi content:felix 2009-8-12 13:21:39 org.apache.coyote.http11.Http11Protocol init 信息: Initializing Coyote HTTP/1.1 on http-8080 2009-8-12 13:21:40 org.apache.coyote.http11.Http11Protocol init 信息: Initializing Coyote HTTP/1.1 on http-8443 2009-8-12 13:21:40 org.apache.catalina.startup.Catalina load 信息: Initialization processed in 1748 ms 2009-8-12 13:21:41 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent 信息: Starting osgi service. 2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start 信息: ********************************* 2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start 信息: catalina home is E:\Cluster\apache-tomcat-6.0.18 2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start 信息: osgi home is E:\Cluster\apache-tomcat-6.0.18\osgi\felix 2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start 信息: ******user.dir is E:\Cluster\apache-tomcat-6.0.18
Welcome to Felix. =================
-> 2009-8-12 13:21:42 org.apache.catalina.core.StandardService start 信息: Starting service Catalina 2009-8-12 13:21:42 org.apache.catalina.core.StandardEngine start 信息: Starting Servlet Engine: Apache Tomcat/6.0.18 2009-8-12 13:21:42 org.apache.catalina.loader.WebappLoader start 信息: Dual registration of jndi stream handler: factory already defined 2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start 信息: Starting Coyote HTTP/1.1 on http-8080 2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start 信息: Starting Coyote HTTP/1.1 on http-8443 2009-8-12 13:21:44 org.apache.jk.common.ChannelSocket init 信息: JK: ajp13 listening on /0.0.0.0:8009 2009-8-12 13:21:44 org.apache.jk.server.JkMain start 信息: Jk running ID=0 time=0/47 config=null 2009-8-12 13:21:44 org.apache.catalina.startup.Catalina start 信息: Server startup in 3882 ms -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) -> |
Step2.安装bundle。
-> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user_1.0.0.jar Bundle ID: 39 -> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user.db_1.0.0.jar Bundle ID: 40 -> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user.file_1.0.0.jar Bundle ID: 41 -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Installed ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Installed ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Installed ] [ 1] User File Implement Plug-in (1.0.0) -> |
Step3.访问web应用,http://localhost:8080/webDemo/。由于没有启动OSGi服务,故出现500异常页面,错误原因是没有找到服务。
root cause com.dinsotne.web.osgi.IllegalServiceException: Cann't find out osgi service:com.dinstone.demo.user.IUserService com.dinsotne.web.osgi.OsgiServiceInvocationHandler.invoke(OsgiServiceInvocationHandler.java:30) $Proxy0.getUserName(Unknown Source) com.dinsotne.web.demo.UserServiceFacade.getUserName(UserServiceFacade.java:14) org.apache.jsp.index_jsp._jspService(index_jsp.java:64) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) |
Step4.启动User DB Implement Plug-in服务,激活User模块的DB实现。
->ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Installed ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Installed ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Installed ] [ 1] User File Implement Plug-in (1.0.0) -> start 40 -> ps -s START LEVEL 1 ID State Level Symbolic name [ 0] [Active ] [ 0] org.apache.felix.framework (1.6.0) [ 25] [Active ] [ 1] org.apache.felix.shell (1.2.0) [ 26] [Active ] [ 1] org.apache.felix.shell.tui (1.2.0) [ 27] [Active ] [ 1] org.apache.felix.bundlerepository (1.4.0) [ 39] [Resolved ] [ 1] com.dinstone.demo.user (1.0.0) [ 40] [Active ] [ 1] com.dinstone.demo.user.db (1.0.0) [ 41] [Installed ] [ 1] com.dinstone.demo.user.file (1.0.0) -> |
访问http://localhost:8080/webDemo/。页面显示:
Step5. 启动User File Implement Plug-in服务,激活User模块的File实现。
-> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Resolved ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Active ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Installed ] [ 1] User File Implement Plug-in (1.0.0) -> start 41 -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Resolved ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Active ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Active ] [ 1] User File Implement Plug-in (1.0.0) -> |
访问http://localhost:8080/webDemo/。页面显示:
Step6.现在停止User DB Implement Plug-in服务。
-> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Resolved ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Active ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Active ] [ 1] User File Implement Plug-in (1.0.0) -> stop 40 -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (1.6.0) [ 25] [Active ] [ 1] Apache Felix Shell Service (1.2.0) [ 26] [Active ] [ 1] Apache Felix Shell TUI (1.2.0) [ 27] [Active ] [ 1] Apache Felix Bundle Repository (1.4.0) [ 39] [Resolved ] [ 1] User Model Interface Plug-in (1.0.0) [ 40] [Resolved ] [ 1] User DB Implement Plug-in (1.0.0) [ 41] [Active ] [ 1] User File Implement Plug-in (1.0.0) -> |
访问http://localhost:8080/webDemo/。页面显示:
4.6 停止Tomcat服务器
重新打开一个命令行窗口,切换到${Tomcat_Home}\bin目录下。执行:
E:\Cluster\apache-tomcat-6.0.18\bin>shutdown.bat |
Tomcat服务器关闭。
5结论
通过以上的测试,我们发现以上的实现基本符合最初的设想:
l OSGi的集成对Tomcat几乎是透明的。
l OSGi的所有优点。
l Web表现和业务逻辑的完全分离。
l 基于模块化服务的编程模型。
同时,我们也发现了一些问题:
l Web层没有支持模块化、可热插拔的编程模型。
l OSGi层的服务日志跟web层的日志分离增加了维护的难度。
l 该集成方式没有经严格测试,虽然已经有产品应用了。
附录:
1.测试Demo
…
2.源码工程
…