Spring DM集成Strtus2(一)

要完成Spring DM与Struts2的集成,主要完成两件事

  • 将Struts2集成到OSGi环境中。
  • 将Spring DM与Struts2集成,使Struts2可以使用Spring DM中定义的Bean。

此文章采用的方法不是Spring DM Web Extender的方式,由Spring DM Web是将工程手动注册到Web容器中,暂时只支持tomcat与jetty。

 

Struts2集成到OSGi环境中

        这步的目的是让Struts2的bundle可以读到其实bundle下的Struts配置文件,由于Struts2本身只处理了classpath下面的三类配置文件,分别为struts-default.xml、struts-plugin.xml、struts.xml文件,所以首先我们要增加读取bundle下面配置文件的ConfigurationProvider,代码在org.apache.struts2.dispatcher.Dispatcher,将此类的源代码找出来,然后修改private void init_TraditionalXmlConfigurations()方法

 

 private void init_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config");
        if (configPaths == null) {
            configPaths = DEFAULT_CONFIGURATION_PATHS;
        }
        String[] files = configPaths.split("\\s*[,]\\s*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
                } else {
                    configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
        //FIXME 增加读取bundle中配置文件的类。
        configurationManager.addContainerProvider(new OSGiXmlConfigurationProvider("struts_osgi.xml",false,servletContext));
    }

 

 其中OSGiXmlConfigurationProvider的代码见附件, 主要的代码在loadConfigurationFiles方法中

Bundle[] bundles=Activator.getContext().getBundles();
			ByteArrayOutputStream bos=new ByteArrayOutputStream();
			for(Bundle bundle:bundles){
				try {
					//不加载本bundle的struts.xml文件
					if(bundle.getSymbolicName().equals(Activator.getContext().getBundle().getSymbolicName())) continue;
					url=bundle.getEntry(DEFAULT_CONFIG_NAME);
					if(url==null) continue;
					is=url.openStream();
					IOUtils.copy(is, bos);
					is=new ByteArrayInputStream(bos.toByteArray());
					InputSource in = new InputSource(is);
					
					in.setSystemId(is.toString());
					Document doc=DomHelper.parse(in,dtdMappings);
					try{
						//增加默认名称空间
						addDefaultNamespace(doc,bundle.getHeaders().get(WEB_CONTEXT),HashFile.getHash(bos.toByteArray()),bundle.getBundleId());
					}catch(Exception e){
						LOG.error("增加包名到缓存失败", e, new String[]{});
					}
					docs.add(doc);
				} catch (IOException e) {
					LOG.error("加载ID为"+bundle.getBundleId()+" 的bundle中的配置文件失败!", e, new String[]{});
				}finally{
					if(is!=null){
						try {
							is.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					if(bos!=null){
						try {
							bos.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}

 接下来就是注册Struts2的servlet,由于采用的是Equinox的http实现,所以要用HttpService来注册

package com.yinhai.osgi.web.struts2;

import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ng.servlet.StrutsServlet;
import org.eclipse.equinox.http.helper.BundleEntryHttpContext;
import org.eclipse.equinox.http.helper.ContextPathServletAdaptor;
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.util.tracker.ServiceTracker;

/**
 * 用于注册struts2的servlet和web bundle的上下文。
 * @author Dream.Lee
 * @version 2013-6-5
 */
public class StrutsController implements BundleListener {
	
	private static Logger logger=Logger.getLogger(StrutsController.class);
	public static final String WEB_CONTEXT="Web-Context";
	
	public static final String STATIC_SUBFIX="_res";

	private HttpService httpService;
	
	public static final String WEB_CONTENT_PATH = "/WebContent";

	public void activate(ComponentContext context) {
		registerController("/*.do");
		//对已有的bundle进行web上下文注册
		Bundle[] bundles=Activator.getContext().getBundles();
		for(Bundle bundle:bundles){
			if(bundle.getHeaders().get(WEB_CONTEXT)!=null&&bundle.getState()==Bundle.ACTIVE){
				try {
					ServiceTracker<HttpService, HttpService> sTracker=new ServiceTracker<HttpService, HttpService>(bundle.getBundleContext(), HttpService.class.getName(), null);
					sTracker.open();
					HttpService httpService=sTracker.getService();
					if(httpService!=null){
						httpService.registerResources(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX,WEB_CONTENT_PATH,
								 null);
						// 注册JSP文件
						HttpContext commonContext = new BundleEntryHttpContext(
								bundle, WEB_CONTENT_PATH);
						Servlet adaptedJspServlet = new ContextPathServletAdaptor(
								new JspServlet(bundle,
										WEB_CONTENT_PATH), bundle.getHeaders().get(
										WEB_CONTEXT));
						httpService.registerServlet(
								bundle.getHeaders().get(WEB_CONTEXT) + "/*.jsp",
								adaptedJspServlet, null, commonContext);
					}
//					sTracker.close();
				} catch (NamespaceException e) {
					e.printStackTrace();
				} catch (ServletException e) {
					e.printStackTrace();
				}
			}
		}
		Activator.getContext().addBundleListener(this);
		Activator.getContext().addBundleListener(new SynchronousBundleListener() {
			
			@SuppressWarnings({ "rawtypes", "unchecked" })
			@Override
			public void bundleChanged(BundleEvent event) {
				Bundle bundle=event.getBundle();
				if (bundle.getHeaders().get(WEB_CONTEXT) != null) {
					switch(event.getType()){
						case BundleEvent.STOPPING:
							ServiceReference sf=bundle.getBundleContext().getServiceReference(HttpService.class.getName());
							HttpService httpService = (HttpService) bundle
									.getBundleContext().getService(sf);
							try{
								httpService.unregister(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX);
								logger.info("卸载"+bundle.getHeaders().get(WEB_CONTEXT));
							}catch(Exception e){
								logger.info("卸载失败:"+bundle.getHeaders().get(WEB_CONTEXT), e);
							}finally{
								bundle.getBundleContext().ungetService(sf);
							}
							break;
					}
				}
			}
		});
	}

	public void setHttpService(HttpService httpService) {
		this.httpService = httpService;
	}


	private void registerController(String webcontext) {
		try {
			StrutsServlet controller = new StrutsServlet();
			httpService.registerServlet(webcontext, controller, null, null);
			controller.init();
			logger.info("已注册:" + webcontext);
		} catch (Exception e) {
			logger.error("注册扩展的:" + webcontext + "失败", e);
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void bundleChanged(BundleEvent event) {
		Bundle bundle = event.getBundle();
		if (bundle.getHeaders().get(WEB_CONTEXT) != null) {
			if (event.getType() == BundleEvent.STARTED) {
				logger.info("注册 "
						+ bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX + ","
						+ bundle.getHeaders().get(WEB_CONTEXT)
						+ "/*.jsp");
				BundleContext context = bundle.getBundleContext();
				ServiceReference sf=context.getServiceReference(HttpService.class.getName());
				HttpService httpService = (HttpService) bundle
						.getBundleContext().getService(sf);
				try {
					// 注册静态文件
					httpService.registerResources(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX,
					 WEB_CONTENT_PATH, null);

					// 注册JSP文件
					Servlet adaptedJspServlet = new ContextPathServletAdaptor(
							new JspServlet(bundle,
									WEB_CONTENT_PATH), bundle
									.getHeaders().get(WEB_CONTEXT));
					httpService.registerServlet(bundle.getHeaders()
							.get(WEB_CONTEXT) + "/*.jsp",
							adaptedJspServlet, null, null);
				} catch (NamespaceException e) {
					e.printStackTrace();
				} catch (ServletException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 此类采用声明式的方式发布,配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<component name="strutscontroller">
	<implementation class="com.yinhai.osgi.web.struts2.StrutsController"/>
	<reference name="HttpService" interface="org.osgi.service.http.HttpService" bind="setHttpService" unbind="unsetHttpService" policy="dynamic"/>
</component>

 

你可能感兴趣的:(struts2,osgi,SpringDM)