001: /*
002: * Copyright (c) 2005 Your Corporation. All Rights Reserved.
003: */
004:
005: /*
006: * Created by IntelliJ IDEA.
007: * User: Jacques
008: * Date: Dec 20, 2005
009: * Time: 11:58:57 PM
010: */
011: package org.strutsspring;
012:
013: import java.io.ByteArrayInputStream;
014: import java.io.InputStream;
015: import javax.servlet.ServletContext;
016: import javax.servlet.ServletException;
017: import javax.xml.parsers.DocumentBuilderFactory;
018: import javax.xml.parsers.ParserConfigurationException;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022: import org.apache.struts.action.ActionServlet;
023: import org.apache.struts.action.PlugIn;
024: import org.apache.struts.config.ActionConfig;
025: import org.apache.struts.config.ModuleConfig;
026: import org.springframework.beans.BeansException;
027: import org.springframework.beans.factory.BeanDefinitionStoreException;
028: import org.springframework.beans.factory.BeanFactory;
029: import org.springframework.beans.factory.config.BeanDefinitionHolder;
030: import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
031: import org.springframework.beans.factory.support.BeanDefinitionRegistry;
032: import org.springframework.beans.factory.support.DefaultListableBeanFactory;
033: import org.springframework.beans.factory.support.AbstractBeanDefinition;
034: import org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser;
035: import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
036: import org.springframework.core.io.InputStreamResource;
037: import org.springframework.core.io.Resource;
038: import org.springframework.web.context.support.WebApplicationContextUtils;
039: import org.springframework.context.ApplicationContextException;
040: import org.w3c.dom.Document;
041: import org.w3c.dom.Element;
042:
043: /**
044: * Initializes Spring bean factory and makes it available through the servlet
045: * context
046: *
047: * @author Don Brown
048: * @version $Revision: 1.4 $ $Date: 2005/03/31 12:16:05 $
049: */
050:
051: public final class SpringPlugIn implements PlugIn {
052:
053: /**
054: * The key the factory is stored under in the servlet context
055: */
056: public static final String BEAN_FACTORY = "org.twdata.struts.SpringPlugin.BEAN_FACTORY";
057:
058: /**
059: * The logging instance
060: */
061: private Log log = LogFactory.getLog(this .getClass());
062:
063: /**
064: * The location of the Spring bean configuration file
065: */
066: private final static String FILENAME = "/WEB-INF/struts-config.xml";
067:
068: /**
069: * The servlet context
070: */
071: private ServletContext context = null;
072: public static final String EMPTY_SPRING_CONTEXT_FILE = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
073: + "<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \"http://www.springframework.org/dtd/spring-beans.dtd\">\n"
074: + "<beans/>";
075:
076: /**
077: * Gracefully remove the Spring bean factory
078: */
079: public void destroy() {
080: log.info("Destroying spring plugin");
081: DefaultListableBeanFactory factory = getBeanFactory();
082: if (factory != null) {
083: factory.destroySingletons();
084: }
085: removeBeanFactory();
086: context = null;
087: }
088:
089: /**
090: * Initialize and load the Spring bean factory
091: *
092: * @param servlet The ActionServlet for this web application
093: * @param config The ApplicationConfig for our owning module
094: * @throws javax.servlet.ServletException if we cannot configure ourselves correctly
095: */
096: public void init(ActionServlet servlet, ModuleConfig config)
097: throws ServletException {
098:
099: log.info("Initializing spring plug in from '" + FILENAME + "'");
100:
101: context = servlet.getServletContext();
102:
103: if (getBeanFactory() == null) {
104: setBeanFactory(createFactory(servlet, config));
105: }
106: }
107:
108: private void setBeanFactory(BeanFactory factory) {
109: context.setAttribute(BEAN_FACTORY, factory);
110: }
111:
112: public DefaultListableBeanFactory getBeanFactory() {
113: return (DefaultListableBeanFactory) context
114: .getAttribute(BEAN_FACTORY);
115: }
116:
117: private void removeBeanFactory() {
118: context.removeAttribute(BEAN_FACTORY);
119: }
120:
121: private BeanFactory createFactory(ActionServlet servlet,
122: ModuleConfig config) throws ServletException {
123: try {
124: BeanFactory parentFactory = WebApplicationContextUtils
125: .getRequiredWebApplicationContext(context);
126: DefaultListableBeanFactory factory = new DefaultListableBeanFactory(
127: parentFactory);
128: XmlBeanDefinitionReader reader = new ActionBeanXmlBeanDefinitionReader(
129: config, factory);
130: InputStream is = new ByteArrayInputStream(
131: EMPTY_SPRING_CONTEXT_FILE.getBytes());
132: reader.loadBeanDefinitions(new InputStreamResource(is,
133: FILENAME));
134:
135: factory.preInstantiateSingletons();
136: return factory;
137: } catch (BeansException ex) {
138: log.error(ex, ex);
139: throw new ServletException(
140: "Unable to initialize Spring bean factory");
141: }
142: }
143:
144: private Element getBeanDefinitionElement(SpringActionMapping mapping) {
145: Element element = mapping.getSpringBeanXml();
146: if (element == null) {
147: element = createElement("bean");
148: }
149: element.setAttribute("id", mapping.getPath());
150: element.setAttribute("class", mapping.getBeanType());
151: return element;
152: }
153:
154: private Element createElement(String tagName) throws BeansException {
155: try {
156: return DocumentBuilderFactory.newInstance()
157: .newDocumentBuilder().newDocument().createElement(
158: tagName);
159: } catch (ParserConfigurationException e) {
160: throw new ApplicationContextException(
161: "problem creating Element", e);
162: }
163: }
164:
165: private class MyXmlBeanDefinitionParser extends
166: DefaultXmlBeanDefinitionParser {
167: public BeanDefinitionHolder parseBeanDefinitionElement(
168: Element ele) {
169: return super .parseBeanDefinitionElement(ele, false);
170: }
171: }
172:
173: private class ActionBeanXmlBeanDefinitionReader extends
174: XmlBeanDefinitionReader {
175: private ModuleConfig config;
176:
177: public ActionBeanXmlBeanDefinitionReader(ModuleConfig config,
178: BeanFactory factory) {
179: super ((BeanDefinitionRegistry) factory);
180: this .config = config;
181: }
182:
183: public int registerBeanDefinitions(Document doc,
184: Resource resource) throws BeansException {
185: MyXmlBeanDefinitionParser parser = new MyXmlBeanDefinitionParser();
186: int beanCount = parser.registerBeanDefinitions(this , doc,
187: resource);
188: beanCount += registerActionBeanDefinitions(parser, config);
189: return beanCount;
190: }
191:
192: private int registerActionBeanDefinitions(
193: MyXmlBeanDefinitionParser parser, ModuleConfig config) {
194: ActionConfig[] actionConfigs = config.findActionConfigs();
195: int beanCount = 0;
196: for (int i = 0; i < actionConfigs.length; i++) {
197: if (actionConfigs[i] instanceof SpringActionMapping) {
198: registerActionBeanDefinition(parser,
199: (SpringActionMapping) actionConfigs[i]);
200: beanCount++;
201: }
202: }
203: return beanCount;
204: }
205:
206: private void registerActionBeanDefinition(
207: MyXmlBeanDefinitionParser parser,
208: SpringActionMapping mapping) {
209: log.debug("registering bean for action " + mapping);
210: Element element = getBeanDefinitionElement(mapping);
211: try {
212: BeanDefinitionHolder holder = parser
213: .parseBeanDefinitionElement(element);
214: AbstractBeanDefinition def = (AbstractBeanDefinition) holder
215: .getBeanDefinition();
216: if (def.getAutowireMode() == AbstractBeanDefinition.AUTOWIRE_NO)
217: def
218: .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
219: BeanDefinitionReaderUtils.registerBeanDefinition(
220: holder, getBeanFactory());
221:
222: } catch (BeanDefinitionStoreException e) {
223: BeanDefinitionStoreException ex = new BeanDefinitionStoreException(
224: "struts config", mapping.getPath(), e
225: .getMessage());
226: ex.setStackTrace(e.getStackTrace());
227: throw ex;
228: }
229: }
230:
231: }
232: }
|