001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.spring;
017:
018: import java.lang.reflect.Method;
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.Properties;
024:
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027: import org.directwebremoting.create.NewCreator;
028: import org.directwebremoting.filter.ExtraLatencyAjaxFilter;
029: import org.springframework.beans.FatalBeanException;
030: import org.springframework.beans.PropertyValue;
031: import org.springframework.beans.factory.BeanFactory;
032: import org.springframework.beans.factory.BeanInitializationException;
033: import org.springframework.beans.factory.HierarchicalBeanFactory;
034: import org.springframework.beans.factory.config.BeanDefinition;
035: import org.springframework.beans.factory.config.BeanDefinitionHolder;
036: import org.springframework.beans.factory.config.RuntimeBeanReference;
037: import org.springframework.beans.factory.support.BeanDefinitionBuilder;
038: import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
039: import org.springframework.beans.factory.support.BeanDefinitionRegistry;
040: import org.springframework.beans.factory.support.ManagedList;
041: import org.springframework.beans.factory.support.ManagedMap;
042: import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
043: import org.springframework.beans.factory.xml.BeanDefinitionParser;
044: import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
045: import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
046: import org.springframework.beans.factory.xml.ParserContext;
047: import org.springframework.util.ClassUtils;
048: import org.springframework.util.StringUtils;
049: import org.springframework.util.xml.DomUtils;
050: import org.w3c.dom.Element;
051: import org.w3c.dom.Node;
052: import org.w3c.dom.NodeList;
053:
054: /**
055: * The Spring namespace handler which handles all elements that are defined as
056: * part of the DWR namespace, except <dwr:annotation-config />. <br/>
057: * The DWR namespace is defined in the <code>spring-dwr-X.X.xsd</code> file. All
058: * elements that are encountered in Spring configuration files are automatically
059: * converted to their actual bean representation in the Spring bean registry.
060: *
061: * @author Erik Wiersma
062: * @author Bram Smeets
063: * @author Jose Noheda
064: * @author Joe Walker [joe at getahead dot ltd dot uk]
065: */
066: public abstract class DwrNamespaceHandler extends
067: NamespaceHandlerSupport {
068: /* (non-Javadoc)
069: * @see org.springframework.beans.factory.xml.NamespaceHandler#init()
070: */
071: public void init() {
072: // register bean definition parsers and decorators for all dwr namespace elements
073: registerBeanDefinitionParser("configuration",
074: new ConfigurationBeanDefinitionParser());
075: registerBeanDefinitionParser("controller",
076: new ControllerBeanDefinitionParser());
077: registerBeanDefinitionParser("url-mapping",
078: new UrlMappingBeanDefinitionParser());
079: registerBeanDefinitionParser("proxy-ref",
080: new ProxyBeanDefinitionParser());
081:
082: registerBeanDefinitionDecorator("init",
083: new InitDefinitionDecorator());
084: registerBeanDefinitionDecorator("create",
085: new CreatorBeanDefinitionDecorator());
086: registerBeanDefinitionDecorator("convert",
087: new ConverterBeanDefinitionDecorator());
088: registerBeanDefinitionDecorator("signatures",
089: new SignaturesBeanDefinitionDecorator());
090: registerBeanDefinitionDecorator("remote",
091: new RemoteBeanDefinitionDecorator());
092: }
093:
094: protected static BeanDefinition registerSpringConfiguratorIfNecessary(
095: BeanDefinitionRegistry registry) {
096: if (!registry
097: .containsBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID)) {
098: BeanDefinitionBuilder builder = BeanDefinitionBuilder
099: .rootBeanDefinition(SpringConfigurator.class);
100: builder.addPropertyValue("creators", new ManagedMap());
101: builder.addPropertyValue("converters", new ManagedMap());
102: registry.registerBeanDefinition(
103: DEFAULT_SPRING_CONFIGURATOR_ID, builder
104: .getBeanDefinition());
105: }
106: return registry
107: .getBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID);
108: }
109:
110: /**
111: * Registers a new {@link org.directwebremoting.extend.Creator} in the registry using name <code>javascript</code>.
112: * @param registry The definition of all the Beans
113: * @param javascript The name of the bean in the registry.
114: * @param creatorConfig
115: * @param params
116: * @param children The node list to check for nested elements
117: */
118: @SuppressWarnings("unchecked")
119: protected void registerCreator(BeanDefinitionRegistry registry,
120: String javascript, BeanDefinitionBuilder creatorConfig,
121: Map<String, String> params, NodeList children) {
122: registerSpringConfiguratorIfNecessary(registry);
123:
124: List<String> includes = new ArrayList<String>();
125: creatorConfig.addPropertyValue("includes", includes);
126:
127: List<String> excludes = new ArrayList<String>();
128: creatorConfig.addPropertyValue("excludes", excludes);
129:
130: Properties auth = new Properties();
131: creatorConfig.addPropertyValue("auth", auth);
132:
133: // check to see if there are any nested elements here
134: for (int i = 0; i < children.getLength(); i++) {
135: Node node = children.item(i);
136:
137: if (node.getNodeType() == Node.TEXT_NODE
138: || node.getNodeType() == Node.COMMENT_NODE) {
139: continue;
140: }
141:
142: Element child = (Element) node;
143:
144: if ("dwr:latencyfilter".equals(node.getNodeName())) {
145: BeanDefinitionBuilder beanFilter = BeanDefinitionBuilder
146: .rootBeanDefinition(ExtraLatencyAjaxFilter.class);
147: beanFilter.addPropertyValue("delay", child
148: .getAttribute("delay"));
149: BeanDefinitionHolder holder2 = new BeanDefinitionHolder(
150: beanFilter.getBeanDefinition(),
151: "__latencyFilter_" + javascript);
152: BeanDefinitionReaderUtils.registerBeanDefinition(
153: holder2, registry);
154:
155: ManagedList filterList = new ManagedList();
156: filterList.add(new RuntimeBeanReference(
157: "__latencyFilter_" + javascript));
158: creatorConfig.addPropertyValue("filters", filterList);
159: } else if ("dwr:include".equals(node.getNodeName())) {
160: includes.add(child.getAttribute("method"));
161: } else if ("dwr:exclude".equals(node.getNodeName())) {
162: excludes.add(child.getAttribute("method"));
163: } else if ("dwr:auth".equals(node.getNodeName())) {
164: auth.setProperty(child.getAttribute("method"), child
165: .getAttribute("role"));
166: } else if ("dwr:convert".equals(node.getNodeName())) {
167: Element element = (Element) node;
168: String type = element.getAttribute("type");
169: String className = element.getAttribute("class");
170:
171: ConverterConfig converterConfig = new ConverterConfig();
172: converterConfig.setType(type);
173: parseConverterSettings(converterConfig, element);
174: lookupConverters(registry).put(className,
175: converterConfig);
176: } else if ("dwr:filter".equals(node.getNodeName())) {
177: Element element = (Element) node;
178: String filterClass = element.getAttribute("class");
179: BeanDefinitionBuilder beanFilter;
180: try {
181: beanFilter = BeanDefinitionBuilder
182: .rootBeanDefinition(ClassUtils
183: .forName(filterClass));
184: } catch (ClassNotFoundException e) {
185: throw new IllegalArgumentException(
186: "DWR filter class '"
187: + filterClass
188: + "' was not found. "
189: + "Check the class name specified in <dwr:filter class=\""
190: + filterClass + "\" /> exists");
191: }
192: BeanDefinitionHolder holder2 = new BeanDefinitionHolder(
193: beanFilter.getBeanDefinition(), "__filter_"
194: + filterClass + "_" + javascript);
195: BeanDefinitionReaderUtils.registerBeanDefinition(
196: holder2, registry);
197:
198: ManagedList filterList = new ManagedList();
199: filterList.add(new RuntimeBeanReference("__filter_"
200: + filterClass + "_" + javascript));
201: creatorConfig.addPropertyValue("filters", filterList);
202: } else if ("dwr:param".equals(node.getNodeName())) {
203: Element element = (Element) node;
204: String name = element.getAttribute("name");
205: String value = element.getAttribute("value");
206: params.put(name, value);
207: } else {
208: throw new RuntimeException(
209: "an unknown dwr:remote sub node was fouund: "
210: + node.getNodeName());
211: }
212: }
213: creatorConfig.addPropertyValue("params", params);
214:
215: String creatorConfigName = "__" + javascript;
216: BeanDefinitionHolder holder3 = new BeanDefinitionHolder(
217: creatorConfig.getBeanDefinition(), creatorConfigName);
218: BeanDefinitionReaderUtils.registerBeanDefinition(holder3,
219: registry);
220:
221: lookupCreators(registry).put(javascript,
222: new RuntimeBeanReference(creatorConfigName));
223: }
224:
225: protected class ConfigurationBeanDefinitionParser implements
226: BeanDefinitionParser {
227: /* (non-Javadoc)
228: * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
229: */
230: @SuppressWarnings("unchecked")
231: public BeanDefinition parse(Element element,
232: ParserContext parserContext) {
233: BeanDefinitionRegistry registry = parserContext
234: .getRegistry();
235: BeanDefinition beanDefinition = registerSpringConfiguratorIfNecessary(registry);
236:
237: Element initElement = DomUtils.getChildElementByTagName(
238: element, "init");
239: if (initElement != null) {
240: decorate(initElement,
241: new BeanDefinitionHolder(beanDefinition,
242: DEFAULT_SPRING_CONFIGURATOR_ID),
243: parserContext);
244: }
245:
246: List<Element> createElements = DomUtils
247: .getChildElementsByTagName(element, "create");
248: for (Element createElement : createElements) {
249: decorate(createElement,
250: new BeanDefinitionHolder(beanDefinition,
251: DEFAULT_SPRING_CONFIGURATOR_ID),
252: parserContext);
253: }
254:
255: List<Element> convertElements = DomUtils
256: .getChildElementsByTagName(element, "convert");
257: for (Element convertElement : convertElements) {
258: decorate(convertElement,
259: new BeanDefinitionHolder(beanDefinition,
260: DEFAULT_SPRING_CONFIGURATOR_ID),
261: parserContext);
262: }
263:
264: List<Element> signatureElements = DomUtils
265: .getChildElementsByTagName(element, "signatures");
266: for (Element signatureElement : signatureElements) {
267: decorate(signatureElement,
268: new BeanDefinitionHolder(beanDefinition,
269: DEFAULT_SPRING_CONFIGURATOR_ID),
270: parserContext);
271: }
272:
273: return beanDefinition;
274: }
275: }
276:
277: protected static class ControllerBeanDefinitionParser implements
278: BeanDefinitionParser {
279: /* (non-Javadoc)
280: * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
281: */
282: @SuppressWarnings("unchecked")
283: public BeanDefinition parse(Element element,
284: ParserContext parserContext) {
285: BeanDefinitionBuilder dwrController = BeanDefinitionBuilder
286: .rootBeanDefinition(DwrController.class);
287: List<Object> configurators = new ManagedList();
288: configurators.add(new RuntimeBeanReference(
289: DEFAULT_SPRING_CONFIGURATOR_ID));
290: dwrController.addPropertyValue("configurators",
291: configurators);
292:
293: String debug = element.getAttribute("debug");
294: if (StringUtils.hasText(debug)) {
295: dwrController.addPropertyValue("debug", debug);
296: }
297:
298: String beanName = element
299: .getAttribute(BeanDefinitionParserDelegate.ID_ATTRIBUTE);
300: String nameAttr = element
301: .getAttribute(BeanDefinitionParserDelegate.NAME_ATTRIBUTE);
302: String[] aliases = null;
303: if (!StringUtils.hasText(beanName)) {
304: beanName = element.getAttribute("name");
305: if (!StringUtils.hasText(beanName)) {
306: beanName = "dwrController"; // Offer a sensible default if no id was specified
307: }
308: } else {
309: String aliasName = element.getAttribute("name");
310: if (StringUtils.hasText(aliasName)) {
311: aliases = StringUtils
312: .tokenizeToStringArray(
313: nameAttr,
314: BeanDefinitionParserDelegate.BEAN_NAME_DELIMITERS);
315: }
316: }
317:
318: parseControllerParameters(dwrController, element);
319:
320: BeanDefinitionHolder holder = new BeanDefinitionHolder(
321: dwrController.getBeanDefinition(), beanName,
322: aliases);
323: BeanDefinitionReaderUtils.registerBeanDefinition(holder,
324: parserContext.getRegistry());
325:
326: return dwrController.getBeanDefinition();
327: }
328:
329: /**
330: * @param dwrControllerDefinition
331: * @param parent
332: */
333: protected void parseControllerParameters(
334: BeanDefinitionBuilder dwrControllerDefinition,
335: Element parent) {
336: NodeList children = parent.getChildNodes();
337: Map<String, String> params = new HashMap<String, String>();
338: for (int i = 0; i < children.getLength(); i++) {
339: Node node = children.item(i);
340:
341: if (node.getNodeType() == Node.TEXT_NODE
342: || node.getNodeType() == Node.COMMENT_NODE) {
343: continue;
344: }
345:
346: Element child = (Element) node;
347: if ("dwr:config-param".equals(child.getNodeName())) {
348: String paramName = child.getAttribute("name");
349: String value = child.getAttribute("value");
350: params.put(paramName, value);
351: } else {
352: throw new RuntimeException(
353: "an unknown dwr:controller sub node was found: "
354: + node.getNodeName());
355: }
356: }
357: dwrControllerDefinition.addPropertyValue("configParams",
358: params);
359: }
360: }
361:
362: /**
363: * Registers a new bean definition based on <dwr:url-mapping /> schema.
364: *
365: * @author Jose Noheda [jose.noheda@gmail.com]
366: */
367: protected class UrlMappingBeanDefinitionParser implements
368: BeanDefinitionParser {
369:
370: /**
371: * Converts <dwr:url-mapping /> tag in the adequate DwrHandlerMapping bean definition.
372: * @param element the <dwr:url-mapping /> tag
373: * @param parserContext access to the registry
374: * @return a DwrHandlerMapping bean definition
375: */
376: public BeanDefinition parse(Element element,
377: ParserContext parserContext) {
378: BeanDefinitionBuilder builder = BeanDefinitionBuilder
379: .rootBeanDefinition(DwrHandlerMapping.class);
380: parserContext.getRegistry().registerBeanDefinition(
381: "DwrAnnotationURLMapper",
382: builder.getBeanDefinition());
383: return parserContext.getRegistry().getBeanDefinition(
384: "DwrAnnotationURLMapper");
385: }
386:
387: }
388:
389: /**
390: * Registers a bean proxy based in <dwr:proxy-ref />
391: *
392: * @author Jose Noheda [jose.noheda@gmail.com]
393: */
394: protected class ProxyBeanDefinitionParser implements
395: BeanDefinitionParser {
396:
397: public BeanDefinition parse(Element element,
398: ParserContext parserContext) {
399: String beanRef = element.getAttribute("bean");
400: BeanDefinitionRegistry registry = parserContext
401: .getRegistry();
402: BeanDefinition beanRefDefinition = findParentDefinition(
403: beanRef, registry);
404: //BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanRefDefinition, beanRef);
405: String javascript = element.getAttribute("javascript");
406: if (!StringUtils.hasText(javascript)) {
407: if (log.isDebugEnabled()) {
408: log
409: .debug("No javascript name provided. Remoting using bean id ["
410: + beanRef + "]");
411: }
412: javascript = StringUtils.capitalize(beanRef);
413: }
414: BeanDefinitionBuilder beanCreator = BeanDefinitionBuilder
415: .rootBeanDefinition(BeanCreator.class);
416: beanCreator.addPropertyValue("beanClass",
417: resolveBeanClassname(beanRefDefinition, registry));
418: beanCreator.addPropertyValue("beanId", beanRef);
419: beanCreator.addDependsOn(beanRef);
420: beanCreator.addPropertyValue("javascript", javascript);
421: BeanDefinitionBuilder creatorConfig = BeanDefinitionBuilder
422: .rootBeanDefinition(CreatorConfig.class);
423: creatorConfig.addPropertyValue("creator", beanCreator
424: .getBeanDefinition());
425: registerCreator(parserContext.getRegistry(), javascript,
426: creatorConfig, new HashMap<String, String>(),
427: element.getChildNodes());
428: return creatorConfig.getBeanDefinition();
429: }
430:
431: }
432:
433: protected class RemoteBeanDefinitionDecorator implements
434: BeanDefinitionDecorator {
435: /**
436: * Registers an <dwr:remote ... /> element.
437: */
438: public BeanDefinitionHolder decorate(Node node,
439: BeanDefinitionHolder definition,
440: ParserContext parserContext) {
441: Element element = (Element) node;
442:
443: String javascript = element.getAttribute("javascript");
444:
445: BeanDefinitionBuilder beanCreator = BeanDefinitionBuilder
446: .rootBeanDefinition(BeanCreator.class);
447:
448: try {
449: String beanClassName = resolveBeanClassname(definition
450: .getBeanDefinition(), parserContext
451: .getRegistry());
452: if (beanClassName == null) {
453: throw new FatalBeanException(
454: "Unabled to find type for beanName '"
455: + definition.getBeanName()
456: + "'. "
457: + "Check your bean has a correctly configured parent or provide a class for "
458: + " the bean definition");
459: }
460: beanCreator.addPropertyValue("beanClass", ClassUtils
461: .forName(beanClassName));
462: } catch (ClassNotFoundException e) {
463: throw new FatalBeanException(
464: "Unable to create DWR bean creator for '"
465: + definition.getBeanName() + "'.", e);
466: }
467:
468: String name = definition.getBeanName();
469: if (name.startsWith("scopedTarget.")) {
470: name = name.substring(name.indexOf(".") + 1);
471: }
472: beanCreator.addPropertyValue("beanId", name);
473: if (!StringUtils.hasText(javascript)) {
474: if (log.isDebugEnabled()) {
475: log
476: .debug("No javascript name provided. Remoting using bean id ["
477: + name + "]");
478: }
479: javascript = StringUtils.capitalize(name);
480: }
481: beanCreator.addPropertyValue("javascript", javascript);
482:
483: BeanDefinitionBuilder creatorConfig = BeanDefinitionBuilder
484: .rootBeanDefinition(CreatorConfig.class);
485: creatorConfig.addPropertyValue("creator", beanCreator
486: .getBeanDefinition());
487: registerCreator(parserContext.getRegistry(), javascript,
488: creatorConfig, new HashMap<String, String>(), node
489: .getChildNodes());
490:
491: return definition;
492: }
493:
494: }
495:
496: /**
497: * Try getting the beanClassName from the definition and if that fails try to get it from
498: * the parent (and even parent BeanFactory if we have to).
499: * @param definition
500: * @param registry
501: * @return class name or null if not found
502: */
503: protected static String resolveBeanClassname(
504: BeanDefinition definition, BeanDefinitionRegistry registry) {
505: String beanClassName = definition.getBeanClassName();
506: while (!StringUtils.hasText(beanClassName)) {
507: try {
508: Method m = definition.getClass().getMethod(
509: "getParentName", new Class[0]);
510: String parentName = (String) m.invoke(definition,
511: new Object[0]);
512: BeanDefinition parentDefinition = findParentDefinition(
513: parentName, registry);
514: beanClassName = parentDefinition.getBeanClassName();
515: definition = parentDefinition;
516: } catch (Exception e) {
517: throw new FatalBeanException(
518: "No parent bean could be found for "
519: + definition, e);
520: }
521: }
522: return beanClassName;
523: }
524:
525: /**
526: *
527: */
528: private static BeanDefinition findParentDefinition(
529: String parentName, BeanDefinitionRegistry registry) {
530: if (registry != null) {
531: if (registry.containsBeanDefinition(parentName)) {
532: return registry.getBeanDefinition(parentName);
533: } else if (registry instanceof HierarchicalBeanFactory) {
534: // Try to get parent definition from the parent BeanFactory. This could return null
535: BeanFactory parentBeanFactory = ((HierarchicalBeanFactory) registry)
536: .getParentBeanFactory();
537: return findParentDefinition(parentName,
538: (BeanDefinitionRegistry) parentBeanFactory);
539: }
540: }
541:
542: // we've exhausted all possibilities
543: return null;
544: }
545:
546: /**
547: *
548: */
549: protected class ConverterBeanDefinitionDecorator implements
550: BeanDefinitionDecorator {
551: /* (non-Javadoc)
552: * @see org.springframework.beans.factory.xml.BeanDefinitionDecorator#decorate(org.w3c.dom.Node, org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.xml.ParserContext)
553: */
554: public BeanDefinitionHolder decorate(Node node,
555: BeanDefinitionHolder definition,
556: ParserContext parserContext) {
557: Element element = (Element) node;
558: String type = element.getAttribute("type");
559: String className = element.getAttribute("class");
560: String javascriptClassName = element
561: .getAttribute("javascript");
562:
563: BeanDefinitionRegistry registry = parserContext
564: .getRegistry();
565:
566: ConverterConfig converterConfig = new ConverterConfig();
567: converterConfig.setType(type);
568: converterConfig.setJavascriptClassName(javascriptClassName);
569: parseConverterSettings(converterConfig, element);
570: lookupConverters(registry).put(className, converterConfig);
571:
572: return definition;
573: }
574: }
575:
576: /**
577: * @param converterConfig
578: * @param parent
579: */
580: protected void parseConverterSettings(
581: ConverterConfig converterConfig, Element parent) {
582: NodeList children = parent.getChildNodes();
583:
584: // check to see if there are any nested elements here
585: for (int i = 0; i < children.getLength(); i++) {
586: Node node = children.item(i);
587:
588: if (node.getNodeType() == Node.TEXT_NODE
589: || node.getNodeType() == Node.COMMENT_NODE) {
590: continue;
591: }
592:
593: Element child = (Element) node;
594: if ("dwr:include".equals(child.getNodeName())) {
595: converterConfig
596: .addInclude(child.getAttribute("method"));
597: } else if ("dwr:exclude".equals(child.getNodeName())) {
598: converterConfig
599: .addExclude(child.getAttribute("method"));
600: }
601: /* TODO Why is this only a property of ObjectConverter?
602: else if (child.getNodeName().equals("dwr:force"))
603: {
604: converterConfig.setForce(Boolean.parseBoolean(child.getAttribute("value")));
605: }
606: */
607: else {
608: throw new RuntimeException(
609: "an unknown dwr:remote sub node was found: "
610: + node.getNodeName());
611: }
612: }
613:
614: }
615:
616: /**
617: * Parse the <code><dwr:init></code> elements
618: */
619: protected class InitDefinitionDecorator implements
620: BeanDefinitionDecorator {
621: /* (non-Javadoc)
622: * @see org.springframework.beans.factory.xml.BeanDefinitionDecorator#decorate(org.w3c.dom.Node, org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.xml.ParserContext)
623: */
624: public BeanDefinitionHolder decorate(Node parent,
625: BeanDefinitionHolder definition,
626: ParserContext parserContext) {
627: Map<String, String> converters = new HashMap<String, String>();
628: Map<String, String> creators = new HashMap<String, String>();
629: NodeList inits = parent.getChildNodes();
630: for (int j = 0; j < inits.getLength(); j++) {
631: Node node = inits.item(j);
632: if (node.getNodeType() == Node.TEXT_NODE
633: || node.getNodeType() == Node.COMMENT_NODE) {
634: continue;
635: }
636:
637: Element child = (Element) inits.item(j);
638: if (child.getNodeName().equals(ELEMENT_CREATOR)) {
639: String id = child.getAttribute(ATTRIBUTE_ID);
640: String className = child
641: .getAttribute(ATTRIBUTE_CLASS);
642: creators.put(id, className);
643: } else if (child.getNodeName()
644: .equals(ELEMENT_CONVERTER)) {
645: String id = child.getAttribute(ATTRIBUTE_ID);
646: String className = child
647: .getAttribute(ATTRIBUTE_CLASS);
648: converters.put(id, className);
649: } else {
650: throw new RuntimeException("An unknown sub node '"
651: + child.getNodeName()
652: + "' was found while parsing dwr:init");
653: }
654: }
655:
656: BeanDefinition configurator = registerSpringConfiguratorIfNecessary(parserContext
657: .getRegistry());
658: configurator.getPropertyValues().addPropertyValue(
659: "creatorTypes", creators);
660: configurator.getPropertyValues().addPropertyValue(
661: "converterTypes", converters);
662:
663: return definition;
664: }
665: }
666:
667: /**
668: * Uses the BeanDefinitionDecorator since we need access to the name of the parent definition??
669: * Register the creatores: spring, new, null, scripted, jsf, struts, pageflow
670: */
671: protected class CreatorBeanDefinitionDecorator implements
672: BeanDefinitionDecorator {
673: /* (non-Javadoc)
674: * @see org.springframework.beans.factory.xml.BeanDefinitionDecorator#decorate(org.w3c.dom.Node, org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.xml.ParserContext)
675: */
676: @SuppressWarnings("unchecked")
677: public BeanDefinitionHolder decorate(Node node,
678: BeanDefinitionHolder definition,
679: ParserContext parserContext) {
680: Element element = (Element) node;
681: String javascript = element.getAttribute("javascript");
682: String creatorType = element.getAttribute("type");
683:
684: BeanDefinitionBuilder creatorConfig = BeanDefinitionBuilder
685: .rootBeanDefinition(CreatorConfig.class);
686:
687: // Configure "known" creators in the CreatorConfig. If unknown then just create the configuration
688: // and leave it up DWR itself to decide if it's a valid creator type
689: BeanDefinitionBuilder creator;
690: Map<String, String> params = new HashMap<String, String>();
691: if ("spring".equals(creatorType)) {
692: // TODO Refactor so that both spring creators use the same code...
693: BeanDefinitionBuilder springCreator = BeanDefinitionBuilder
694: .rootBeanDefinition(BeanCreator.class);
695:
696: springCreator
697: .addPropertyValue("javascript", javascript);
698:
699: NodeList children = element.getChildNodes();
700: for (int i = 0; i < children.getLength(); i++) {
701: Node childNode = children.item(i);
702: if (childNode.getNodeType() == Node.TEXT_NODE
703: || childNode.getNodeType() == Node.COMMENT_NODE) {
704: continue;
705: }
706:
707: Element child = (Element) childNode;
708: String paramName = child.getAttribute("name");
709: String value = child.getAttribute("value");
710: if ("beanName".equals(paramName)
711: || "beanId".equals(paramName)) {
712: springCreator.addPropertyValue("beanId", value);
713: } else {
714: params.put(paramName, value);
715: }
716: }
717:
718: creatorConfig.addPropertyValue("creator", springCreator
719: .getBeanDefinition());
720: } else if ("new".equals(creatorType)) {
721: creator = BeanDefinitionBuilder
722: .rootBeanDefinition(NewCreator.class);
723: creator.addPropertyValue("className", node
724: .getAttributes().getNamedItem("class")
725: .getNodeValue());
726: creator.addPropertyValue("javascript", javascript);
727: creatorConfig.addPropertyValue("creator", creator
728: .getBeanDefinition());
729: } else if ("null".equals(creatorType)) {
730: creatorConfig.addPropertyValue("creatorType", "none");
731: String className = element.getAttribute("class");
732: if (className == null || "".equals(className)) {
733: throw new BeanInitializationException(
734: "'class' is a required attribute for the declaration <dwr:creator type=\"null\""
735: + " javascript=\""
736: + javascript
737: + "\" ... />");
738: }
739: params.put("class", className);
740: } else if ("pageflow".equals(creatorType)) {
741: creatorConfig.addPropertyValue("creatorType",
742: creatorType);
743: } else if ("jsf".equals(creatorType)
744: || "scripted".equals(creatorType)
745: || "struts".equals(creatorType)) {
746: creatorConfig.addPropertyValue("creatorType",
747: creatorType);
748: } else {
749: if (log.isDebugEnabled()) {
750: log.debug("Looking up creator type '" + creatorType
751: + "'");
752: }
753: // TODO We should delay the initialization of the creatorClass until after the bean
754: // definitions have been parsed.
755: BeanDefinition configurator = registerSpringConfiguratorIfNecessary(parserContext
756: .getRegistry());
757: PropertyValue registeredCreators = configurator
758: .getPropertyValues().getPropertyValue(
759: "creatorTypes");
760: Map<String, String> registeredCreatorMap = (Map<String, String>) registeredCreators
761: .getValue();
762: String creatorClass = registeredCreatorMap
763: .get(creatorType);
764: if (creatorClass == null) {
765: // the creator type should have been registered
766: throw new UnsupportedOperationException(
767: "Type "
768: + creatorType
769: + " is not supported "
770: + " or the custom creator has not been registered dwr:init");
771: } else {
772: try {
773: Class<?> clazz = Class.forName(creatorClass);
774: creator = BeanDefinitionBuilder
775: .rootBeanDefinition(clazz);
776: creatorConfig.addPropertyValue("creator",
777: creator.getBeanDefinition());
778: String className = element
779: .getAttribute("class");
780: if (StringUtils.hasText(className)) {
781: params.put("class", className);
782: }
783: } catch (ClassNotFoundException ex) {
784: throw new FatalBeanException(
785: "ClassNotFoundException trying to register "
786: + " creator '"
787: + creatorClass
788: + "' for javascript type '"
789: + javascript
790: + "'. Check the "
791: + " class in the classpath and that the creator is register in dwr:init",
792: ex);
793: }
794: }
795: }
796:
797: registerCreator(parserContext.getRegistry(), javascript,
798: creatorConfig, params, node.getChildNodes());
799:
800: return definition;
801: }
802: }
803:
804: protected class SignaturesBeanDefinitionDecorator implements
805: BeanDefinitionDecorator {
806:
807: public BeanDefinitionHolder decorate(Node node,
808: BeanDefinitionHolder definition,
809: ParserContext parserContext) {
810: BeanDefinitionRegistry registry = parserContext
811: .getRegistry();
812: BeanDefinition config = registerSpringConfiguratorIfNecessary(registry);
813:
814: StringBuffer sigtext = new StringBuffer();
815: NodeList children = node.getChildNodes();
816: for (int i = 0; i < children.getLength(); i++) {
817: Node child = children.item(i);
818: if (child.getNodeType() != Node.TEXT_NODE
819: && child.getNodeType() != Node.CDATA_SECTION_NODE) {
820: log.warn("Ignoring illegal node type: "
821: + child.getNodeType());
822: continue;
823: }
824: sigtext.append(child.getNodeValue());
825: }
826:
827: config.getPropertyValues().addPropertyValue("signatures",
828: sigtext.toString());
829:
830: return definition;
831: }
832:
833: }
834:
835: /**
836: * @param registry
837: * @return Get a list of the defined Creators
838: */
839: @SuppressWarnings("unchecked")
840: protected static Map<String, RuntimeBeanReference> lookupCreators(
841: BeanDefinitionRegistry registry) {
842: BeanDefinition config = registerSpringConfiguratorIfNecessary(registry);
843: return (Map<String, RuntimeBeanReference>) config
844: .getPropertyValues().getPropertyValue("creators")
845: .getValue();
846: }
847:
848: /**
849: * @param registry
850: * @return Get a list of the defined Converters
851: */
852: @SuppressWarnings("unchecked")
853: protected Map<String, ConverterConfig> lookupConverters(
854: BeanDefinitionRegistry registry) {
855: BeanDefinition config = registerSpringConfiguratorIfNecessary(registry);
856: return (Map<String, ConverterConfig>) config
857: .getPropertyValues().getPropertyValue("converters")
858: .getValue();
859: }
860:
861: protected static final String DEFAULT_SPRING_CONFIGURATOR_ID = "__dwrConfiguration";
862:
863: /**
864: * The log stream
865: */
866: protected static final Log log = LogFactory
867: .getLog(DwrNamespaceHandler.class);
868:
869: /*
870: * The element names
871: */
872: private static final String ELEMENT_CONVERTER = "dwr:converter";
873:
874: private static final String ELEMENT_CREATOR = "dwr:creator";
875:
876: /*
877: * The attribute names
878: */
879: private static final String ATTRIBUTE_ID = "id";
880:
881: private static final String ATTRIBUTE_CLASS = "class";
882:
883: }
|