扩展Tomcat支持OSGi应用服务(2)

3.实现步骤

有了以上的分析和设计思路,我们接下来详细描述实现过程及需要注意的地方。

3.1扩展Tomcat,集成OSGi平台

Step1.创建java项目com.dinstone.tomcat.osgi,创建OsgiLifecycleListener类:

package com.dinstone.tomcat.osgi;

imp<wbr>ort</wbr> java.util.logging.Logger;

imp<wbr>ort</wbr> org.apache.catalina.Lifecycle;

imp<wbr>ort</wbr> org.apache.catalina.LifecycleEvent;

imp<wbr>ort</wbr> org.apache.catalina.LifecycleListener;

imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;

publicclass OsgiLifecycleListener implements LifecycleListener {

privatestatic Logger log = Logger.getLogger(OsgiLifecycleListener.class

.getName());

privatestatic OsgiLifecycleListener listener = null;

/**theosgiTypedefaultvalueis'Equixox'.*/

private String osgiType = "Equinox";

private OsgiContent osgiContent = null;

public OsgiLifecycleListener() {

}

publicstatic OsgiLifecycleListener getInstance() {

returnlistener;

}

@Override

publicvoid lifecycleEvent(LifecycleEvent event) {

if (Lifecycle.INIT_EVENT.equals(event.getType())) {

log.info("The osgi content is initialized. Using osgi content:"

+ osgiType);

try {

initContent();

} catch (Exception e) {

e.printStackTrace();

}

} elseif (Lifecycle.START_EVENT.equals(event.getType())) {

try {

log.info("Starting osgi service.");

osgiContent.start();

} catch (Exception e) {

e.printStackTrace();

log.info("Starting the osgi content occured error. "

+ e.getMessage());

}

} elseif (Lifecycle.STOP_EVENT.equals(event.getType())) {

try {

log.info("Stopping osgi service.");

osgiContent.stop();

} catch (Exception e) {

e.printStackTrace();

log.info("Stopping the osgi content occured error. "

+ e.getMessage());

}

}

}

privatevoid initContent() throws Exception {

listener = this;

osgiContent = OsgiContentFactory.getInstance().getOsgiContent(osgiType);

}

public String getOsgiType() {

returnosgiType;

}

publicvoid setOsgiType(String osgiType) {

this.osgiType = osgiType;

}

public OsgiServices getOsgiServices() {

returnosgiContent;

}

publicvoid setOsgiContent(OsgiContent osgiContent) {

this.osgiContent = osgiContent;

}

}

Step2.打开${Tomcat_Home}/conf/server.xml.${Tomcat_Home}Tomcat安装目录,下同。

添加红色部分:

<Server port="8005" shutdown="SHUTDOWN">

<!--APR library loader. Documentation at /docs/apr.html -->

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->

<Listener className="org.apache.catalina.core.JasperListener" />

<!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->

<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<!-- OSGi support for the Tomcat server -->

<Listener className="com.dinstone.tomcat.osgi.OsgiLifecycleListener" osgiType="felix"/>

Step3. 打开${Tomcat_Home}/conf/catalina.properties。修改红色部分:

#

#

# List of comma-separated paths defining the contents of the "common"

# classloader. Prefixes should be used to define what is the repository type.

# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.

# If left as blank,the JVM system loader will be used as Catalina's "common"

# loader.

# Examples:

# "foo": Add this folder as a class repository

# "foo/*.jar": Add all the JARs of the specified folder as class

# repositories

# "foo/bar.jar": Add bar.jar as a class repository

# ${catalina.home}/osgi/equinox/plugins,${catalina.home}/osgi/equinox/plugins/*.jar,

common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/osgi/felix/bin/*.jar

Step4.构建equinox环境。

新建目录:${Tomcat_Home}/osgi/equinox/plugins/,org.eclipse.osgi_3.3.2.R33x_v20080105.jar放于该目录下。

Step5.构建felix环境。

新建目录:${Tomcat_Home}/osgi/felix/,将下载的felix-1.6.0.zip解压到该目录。最终的目录结构如图:

扩展Tomcat支持OSGi应用服务(2) - Dinstone - Dinstone 的技术博客

Step5.创建服务接口:

package com.dinstone.osgi;

publicinterface OsgiServices {

public Object getOSGiService(String serviceName);

public Class<?> getBundleClass(String bundleName, String className)

throws ClassNotFoundException;

}

3.2 发布OSGi服务到JNDI

Step6.创建资源工厂类:

package com.dinstone.tomcat.osgi;

imp<wbr>ort java.util.Enumeration;</wbr>

imp<wbr>ort java.util.Hashtable;</wbr>

imp<wbr>ort java.util.logging.Logger;</wbr>

imp<wbr>ort javax.naming.Context;</wbr>

imp<wbr>ort javax.naming.Name;</wbr>

imp<wbr>ort javax.naming.RefAddr;</wbr>

imp<wbr>ort javax.naming.Reference;</wbr>

imp<wbr>ort javax.naming.spi.ObjectFactory;</wbr>

imp<wbr>ort com.dinstone.osgi.OsgiServices;</wbr>

public class OsgiServicesFactory implements ObjectFactory {

private static Logger log = Logger.getLogger(OsgiServicesFactory.class

.getName());

private OsgiServices osgiServices;

@Override

public Object getObjectInstance(Object obj, Name name, Context nameCtx,

Hashtable<?, ?> environment) throws Exception {

// Customize the bean properties from our attributes

Reference ref = (Reference) obj;

Enumeration<RefAddr> addrs = ref.getAll();

while (addrs.hasMoreElements()) {

RefAddr addr = addrs.nextElement();

String attrName = addr.getType();

String value = (String) addr.getContent();

log.info("the attribute is (" + attrName + " == " + value);

}

initContext();

return osgiServices;

}

private void initContext() {

if (osgiServices == null) {

OsgiLifecycleListener osgilcl = OsgiLifecycleListener.getInstance();

osgiServices = osgilcl.getOsgiServices();

}

}

}

Step7.打开${Tomcat_Home}/conf/context.xml。添加以下内容:

<Resource name="osgi/services" auth="Container"

type="com.dinstone.osgi.OsgiServices"

factory="com.dinstone.tomcat.osgi.OsgiServicesFactory" />

说明:

1. OsgiLifecycleListener为单例对象,主要功能为根据配置信息osgiType来加载不同的OSGi平台,根据事件类型来启动和停止OSGi平台。

2. osgiType必须有get/set方法,Tomcat会注入配置信息。

3.com.dinstone.tomcat.osgi工程编译打包成com.dinstone.tomcat.osgi_1.12.4.jar,将jar放于${Tomcat_Home}/lib目录下。

4.step7中的配置方式意味着所有的应用都可以引用"osgi/services"资源。另外一种方式可以在web应用的发布文件中配置,具体参见其它相关文档。

3.3 Web应用引用JNDI资源

Web应用为了引用JNDI资源,需要使用java的反射机制来调用资源服务。首先我们建立web端得JNDI资源应用API

Step1.创建java项目com.dinsotne.web.osgi,创建JndiOsgiServicesFactory类,负责在JNDI中查找OsgiServices服务。

package com.dinsotne.web.osgi;

imp<wbr>ort javax.naming.Context;</wbr>

imp<wbr>ort javax.naming.InitialContext;</wbr>

imp<wbr>ort javax.naming.NamingException;</wbr>

imp<wbr>ort com.dinstone.osgi.OsgiServices;</wbr>

public class JndiOsgiServicesFactory implements OsgiServicesFactory {

/** JNDI prefix used in a J2EE container */

private static final String CONTAINER_PREFIX = "java:comp/env/";

private String jndiName;

public String getJndiName() {

return jndiName;

}

public void setJndiName(String jndiName) {

this.jndiName = jndiName;

}

public OsgiServices getOsgiServices() {

return (OsgiServices) lookup(getJndiName());

}

private Object lookup(String jndiName) {

String convertedName = convertJndiName(jndiName);

Object jndiObject = null;

try {

Context context = new InitialContext();

jndiObject = context.lookup(convertedName);

} catch (NamingException e) {

throw new IllegalServiceException(

"The JNDI OSGi services name is error.", e);

} catch (Exception e) {

throw new IllegalServiceException(

"The JNDI OSGi services can not be initialed.", e);

}

return jndiObject;

}

private String convertJndiName(String jndiName) {

if (!jndiName.startsWith(CONTAINER_PREFIX)

&& jndiName.indexOf(':') == -1) {

jndiName = CONTAINER_PREFIX + jndiName;

}

return jndiName;

}

}

Step2.web应用的web.xml中添加如下内容:

<resource-env-ref>

<description>osgi services</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>

3.4 Web应用调用OSGi服务

Step3.有了OsgiServices服务后,我们创建OsgiServiceFactory类,负责获取OSGi平台的动态服务。

package com.dinsotne.web.osgi;

imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;

publicclass OsgiServiceFactory {

private OsgiServices services;

public OsgiServiceFactory(OsgiServices services) {

this.services = services;

}

public OsgiServiceFactory() {

}

public <T> T getOsgiService(Class<T> serviceType, String serviceName) {

OsgiServiceInvocationHandler handler = new OsgiServiceInvocationHandler(

services, serviceName);

return JavaProxyObjectFactory.getProxyObject(serviceType, handler);

}

public OsgiServices getServices() {

returnservices;

}

publicvoid setServices(OsgiServices services) {

this.services = services;

}

}

Step4.为了方便Web端得调用,我们创建了类OsgiServiceFacade

package com.dinsotne.web.osgi;

imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;

publicclass OsgiServiceFacade {

publicstatic <T> T getOsgiService(String jndiName, Class<T> serviceType,

String serviceName) {

JndiOsgiServicesFactory factory = new JndiOsgiServicesFactory();

factory.setJndiName(jndiName);

OsgiServices services = factory.getOsgiServices();

OsgiServiceFactory sf = new OsgiServiceFactory(services);

return sf.getOsgiService(serviceType, serviceName);

}

}

Step5.Web调用示例。

publicstatic 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();

}

returnnull;

}

说明:

1.以上的代码应用了java代理和反射技术,其它的代码参见源码。

2. OsgiServiceFactory在获取OSGi平台服务时,使用了java代理。读者可能会疑问,为什么Datasource资源服务的引用就不必使用反射,而我们的OSGi服务就需要使用反射啊?这个都是java的类加载机制惹得祸。对于Datasource资源,它的类型是javax.sql.DataSource,为系统类,且运行在Tomcat中的web应用都使用Tomcat容器的类加载器加载这个类,故web应用中的javax.sql.DataSourceTomcat加载的是同一类。但是,对于OSGi服务类,该类由OSGi容器的类加载器加载,而我们的web应用是不能使用该类加载器加载该类的,故只能通过反射来调用服务了。

3.将项目工程com.dinsotne.web.osgi导出打包:com.dinsotne.web.osgi_1.12.0.jar

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值