Tomcat集成OSGI,并通过JNDI开放Web调用

Tomcat集成OSGi,首先要选择OSGI服务器,我这里采用的是equinox.jar.

第一步开发OSGI的bundle,这里就不说明了.
第二步构建OSGi在Tomcat下的目录结构如图${Tomcat_Home}/lib

Tomcat集成OSGI,并通过JNDI开放Web调用
第三步配置OSGI启动项,配置文件[config.ini]内容如下:
osgi.noShutdown=true
osgi.bundles=reference\:file\:bundles/org.apache.commons.logging_1.0.4.v201101211617.jar@start,reference\:file\:bundles/org.eclipse.osgi.services_3.3.0.v20110513.jar@start,reference\:file\:bundles/DictQuery_1.0.0.jar@start,reference\:file\:bundles/RomoteDictQuery_1.0.0.jar@start,reference\:file\:bundles/LocalDictQuery_1.0.0.jar@start
osgi.bundles.defaultStartLevel=4

第四步关键了,我们把OSGI的生命周期集成到Tomcat容器来管理.
package standard.osgi.jndi;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.eclipse.core.runtime.adaptor.EclipseStarter;
import org.osgi.dictquery.query.QueryService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

public class OsgiListener implements LifecycleListener {
	
	private static Logger log = Logger.getLogger(OsgiListener.class.getName());
	 
    private String osgiType = "Equinox";
    
    private BundleContext bundleContext; 
    
    private static OsgiListener listener = null;
    
    public static OsgiListener getInstance(){
    	return listener;
    }

	public BundleContext getBundleContext() {
		return bundleContext;
	}

	public void setBundleContext(BundleContext bundleContext) {
		this.bundleContext = bundleContext;
	}

	@Override
	public void lifecycleEvent(LifecycleEvent event) {
		if (Lifecycle.AFTER_INIT_EVENT.equals(event.getType())) { 
	           log.info("The osgi content is initialized. Using osgi content:"+ osgiType); 
	           try { 
	             // initContent();
	           } catch (Exception e) {
	        	   log.log(Level.SEVERE, "初始化osgi失败"+e.getCause());
	           }

	       } else if (Lifecycle.START_EVENT.equals(event.getType())) {

	           try {

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

	              EclipseStarter.run(new String[] { "-console" }, null);
	              initContent();
	              log.info("Starting osgi service invoke.");
	            //获取服务
	            //this interface is not the osgi's interface.
	          //	QueryService queryService = null;
	              Object queryService = null; 
	              ServiceReference serviceRef = bundleContext.getServiceReference(QueryService.class.getName());
	              if(null != serviceRef){
	          		queryService = bundleContext.getService(serviceRef);
	          	}
	             Method method =  queryService.getClass().getDeclaredMethod("queryWorld", String.class);
	             Object result = method.invoke(queryService, "sky");
	             System.out.println("11Result is " +new String(result.toString().getBytes(),"GB2312"));

	           } catch (Exception e) {

	              e.printStackTrace();

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

	                     + e.getMessage());

	           }

	       } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {

	           try {

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

	              EclipseStarter.shutdown();

	           } catch (Exception e) { 
	              log.info("Stopping the osgi content occured error. "

	                     + e.getMessage());

	           }

	       }

	}

	/**
	 * 初始化osgi
	 */
	private void initContent() { 
		bundleContext = EclipseStarter.getSystemBundleContext(); 
		listener = this;
	}

}


在web容器启动的时候,启动osgi容量,这里提供了一个简单的调用,通过bundleContext可以获取服务,通过反映可以调用osgi方法,并返回结果.[osgi classLoader is not the web classloader].
启动Tomcat,你会发现启动成功,并成功启动osgi容器,调用成功osgi容量的方法.
当然,这里的bundleContext是可以通过JNDI开放到Tomcat容器下的其他web应用使用的.
那么如何把OSGI包装成JNDI开放出去呢

第一步,开发InitialContext
package standard.osgi.jndi;

import java.util.HashMap;
import java.util.Hashtable;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class MyInitialContext extends InitialContext {
	
	private static HashMap<String, Object> map = new HashMap<String, Object>();  

	public MyInitialContext() throws NamingException {
		super(); 
	}
	
	public MyInitialContext(Hashtable<?,?> environment) throws NamingException {
		super(environment);
	}

	@Override
	public void bind(String name, Object obj) throws NamingException { 
		map.put(name, obj);
	}

	@Override
	public void unbind(String name) throws NamingException {
		map.remove(name);
	}

	@Override
	public Object lookup(String name) throws NamingException {
		return map.get(name);
	} 
}


第二步,开发InitialContextFactory
package standard.osgi.jndi;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;

public class MyInitialContextFactory implements InitialContextFactory{

	@Override
	public Context getInitialContext(Hashtable<?, ?> environment)
			throws NamingException { 
		return new MyInitialContext();
	}

}



第三步,使用我们自定义的JNDI注册我们的OSGI服务,修改上面的initContext方法
	/**
	 * 初始化osgi
	 */
	private void initContent() { 
		bundleContext = EclipseStarter.getSystemBundleContext();  
		try {
			Hashtable env = new Hashtable(); 
			//env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
			env.put(Context.INITIAL_CONTEXT_FACTORY, "standard.osgi.jndi.MyInitialContextFactory");  
			Context ctx = new InitialContext(env);
			ctx.bind("init/context", bundleContext);
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

第四步,这样我们的osgi的bundleContext已经注册到Jndi中了,我们要web中,只需要获取我们自定义的JNDI,获取bundleContext就可以了.
 Hashtable env = new Hashtable(); 
	  			//env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
	  			env.put(Context.INITIAL_CONTEXT_FACTORY, "standard.osgi.jndi.MyInitialContextFactory");  
	  			Context ctx = new InitialContext(env);
	  			BundleContext bundleContextJndi = (BundleContext)ctx.lookup("init/context");
	              Object queryService = null; 
	              ServiceReference serviceRef = bundleContextJndi.getServiceReference(QueryService.class.getName());
	              if(null != serviceRef){
	          		queryService = bundleContextJndi.getService(serviceRef);
	          	}
	             Method method =  queryService.getClass().getDeclaredMethod("queryWorld", String.class);
	             Object result = method.invoke(queryService, "sky");
	             System.out.println("jndi Result is " +new String(result.toString().getBytes(),"GB2312"));


这里没作太多的封装,不过成功的把OSGI封装到Tomcat,再把OSGI通过JNDI开放到各个web应用。

你可能感兴趣的:(tomcat)