All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.directwebremoting.spring.DwrNamespaceHandler Maven / Gradle / Ivy

/*
 * Copyright 2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.directwebremoting.spring;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.directwebremoting.create.NewCreator;
import org.directwebremoting.filter.ExtraLatencyAjaxFilter;
import org.directwebremoting.util.Logger;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * The Spring namespace handler which handles all elements that are defined as
 * part of the DWR namespace. 
* The DWR namespace is defined in the spring-dwr-X.X.xsd file. All * elements that are encountered in Spring configuration files are automatically * converted to their actual bean representation in the Spring bean registry. * * @author Erik Wiersma * @author Bram Smeets * @author Joe Walker [joe at getahead dot ltd dot uk] */ public class DwrNamespaceHandler extends NamespaceHandlerSupport { /* (non-Javadoc) * @see org.springframework.beans.factory.xml.NamespaceHandler#init() */ public void init() { // register bean definition parsers and decorators for all dwr namespace elements registerBeanDefinitionParser("configuration", new ConfigurationBeanDefinitionParser()); registerBeanDefinitionParser("controller", new ControllerBeanDefinitionParser()); registerBeanDefinitionDecorator("init", new InitDefinitionDecorator()); registerBeanDefinitionDecorator("create", new CreatorBeanDefinitionDecorator()); registerBeanDefinitionDecorator("convert", new ConverterBeanDefinitionDecorator()); registerBeanDefinitionDecorator("signatures", new SignaturesBeanDefinitionDecorator()); registerBeanDefinitionDecorator("remote", new RemoteBeanDefinitionDecorator()); } /* * */ protected BeanDefinition registerSpringConfiguratorIfNecessary(BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID)) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SpringConfigurator.class); builder.addPropertyValue("creators", new ManagedMap()); builder.addPropertyValue("converters", new ManagedMap()); registry.registerBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID, builder.getBeanDefinition()); } return registry.getBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID); } /** * Registers a new {@link org.directwebremoting.extend.Creator} in the registry using name javascript. * @param registry The definition of all the Beans * @param javascript The name of the bean in the registry. * @param beanCreator The {@link org.directwebremoting.extend.Creator} to register. * @param children The node list to check for nested elements */ protected void registerCreator(BeanDefinitionRegistry registry, String javascript, BeanDefinitionBuilder creatorConfig, Map params, NodeList children) { registerSpringConfiguratorIfNecessary(registry); List includes = new ArrayList(); creatorConfig.addPropertyValue("includes", includes); List excludes = new ArrayList(); creatorConfig.addPropertyValue("excludes", excludes); Properties auth = new Properties(); creatorConfig.addPropertyValue("auth", auth); // check to see if there are any nested elements here for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.COMMENT_NODE) { continue; } Element child = (Element) node; if (node.getNodeName().equals("dwr:latencyfilter")) { BeanDefinitionBuilder beanFilter = BeanDefinitionBuilder.rootBeanDefinition(ExtraLatencyAjaxFilter.class); beanFilter.addPropertyValue("delay", child.getAttribute("delay")); BeanDefinitionHolder holder2 = new BeanDefinitionHolder(beanFilter.getBeanDefinition(), "__latencyFilter_" + javascript); BeanDefinitionReaderUtils.registerBeanDefinition(holder2, registry); ManagedList filterList = new ManagedList(); filterList.add(new RuntimeBeanReference("__latencyFilter_" + javascript)); creatorConfig.addPropertyValue("filters", filterList); } else if (node.getNodeName().equals("dwr:include")) { includes.add(child.getAttribute("method")); } else if (node.getNodeName().equals("dwr:exclude")) { excludes.add(child.getAttribute("method")); } else if (node.getNodeName().equals("dwr:auth")) { auth.setProperty(child.getAttribute("method"), child.getAttribute("role")); } else if (node.getNodeName().equals("dwr:convert")) { Element element = (Element) node; String type = element.getAttribute("type"); String className = element.getAttribute("class"); ConverterConfig converterConfig = new ConverterConfig(); converterConfig.setType(type); parseConverterSettings(converterConfig, element); lookupConverters(registry).put(className, converterConfig); } else if (node.getNodeName().equals("dwr:filter")) { Element element = (Element) node; String filterClass = element.getAttribute("class"); BeanDefinitionBuilder beanFilter; try { beanFilter = BeanDefinitionBuilder.rootBeanDefinition(ClassUtils.forName(filterClass)); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("DWR filter class '" + filterClass + "' was not found. " + "Check the class name specified in exists"); } BeanDefinitionHolder holder2 = new BeanDefinitionHolder(beanFilter.getBeanDefinition(), "__filter_" + filterClass + "_" + javascript); BeanDefinitionReaderUtils.registerBeanDefinition(holder2, registry); ManagedList filterList = new ManagedList(); filterList.add(new RuntimeBeanReference("__filter_" + filterClass + "_" + javascript)); creatorConfig.addPropertyValue("filters", filterList); } else if (node.getNodeName().equals("dwr:param")) { Element element = (Element) node; String name = element.getAttribute("name"); String value = element.getAttribute("value"); params.put(name, value); } else { throw new RuntimeException("an unknown dwr:remote sub node was fouund: " + node.getNodeName()); } } creatorConfig.addPropertyValue("params", params); String creatorConfigName = "__" + javascript; BeanDefinitionHolder holder3 = new BeanDefinitionHolder(creatorConfig.getBeanDefinition(), creatorConfigName); BeanDefinitionReaderUtils.registerBeanDefinition(holder3, registry); lookupCreators(registry).put(javascript, new RuntimeBeanReference(creatorConfigName)); } protected class ConfigurationBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinition beanDefinition = registerSpringConfiguratorIfNecessary(registry); Element initElement = DomUtils.getChildElementByTagName(element, "init"); if (initElement != null) { decorate(initElement, new BeanDefinitionHolder(beanDefinition, DEFAULT_SPRING_CONFIGURATOR_ID), parserContext); } List createElements = DomUtils.getChildElementsByTagName(element, "create"); Iterator iter = createElements.iterator(); while (iter.hasNext()) { Element createElement = (Element) iter.next(); decorate(createElement, new BeanDefinitionHolder(beanDefinition, DEFAULT_SPRING_CONFIGURATOR_ID), parserContext); } List convertElements = DomUtils.getChildElementsByTagName(element, "convert"); iter = convertElements.iterator(); while (iter.hasNext()) { Element convertElement = (Element) iter.next(); decorate(convertElement, new BeanDefinitionHolder(beanDefinition, DEFAULT_SPRING_CONFIGURATOR_ID), parserContext); } List signatureElements = DomUtils.getChildElementsByTagName(element, "signatures"); for (Iterator i = signatureElements.iterator(); i.hasNext();) { Element signatureElement = (Element) i.next(); decorate(signatureElement, new BeanDefinitionHolder(beanDefinition, DEFAULT_SPRING_CONFIGURATOR_ID), parserContext); } return beanDefinition; } } protected class ControllerBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionBuilder dwrController = BeanDefinitionBuilder.rootBeanDefinition(DwrController.class); List configurators = new ManagedList(); configurators.add(new RuntimeBeanReference(DEFAULT_SPRING_CONFIGURATOR_ID)); dwrController.addPropertyValue("configurators", configurators); String debug = element.getAttribute("debug"); if (StringUtils.hasText(debug)) { dwrController.addPropertyValue("debug", debug); } String beanName = element.getAttribute(BeanDefinitionParserDelegate.ID_ATTRIBUTE); String nameAttr = element.getAttribute(BeanDefinitionParserDelegate.NAME_ATTRIBUTE); String[] aliases = null; if (!StringUtils.hasText(beanName)) { beanName = element.getAttribute("name"); } else { String aliasName = element.getAttribute("name"); if (StringUtils.hasText(aliasName)) { aliases = StringUtils.tokenizeToStringArray(nameAttr, BeanDefinitionParserDelegate.BEAN_NAME_DELIMITERS); } } parseControllerParameters(dwrController, element); BeanDefinitionHolder holder = new BeanDefinitionHolder(dwrController.getBeanDefinition(), beanName, aliases); BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry()); return dwrController.getBeanDefinition(); } protected void parseControllerParameters(BeanDefinitionBuilder dwrControllerDefinition, Element parent) { NodeList children = parent.getChildNodes(); Map params = new HashMap(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.COMMENT_NODE) { continue; } Element child = (Element) node; if (child.getNodeName().equals("dwr:config-param")) { String paramName = child.getAttribute("name"); String value = child.getAttribute("value"); params.put(paramName, value); } else { throw new RuntimeException("an unknown dwr:controller sub node was found: " + node.getNodeName()); } } dwrControllerDefinition.addPropertyValue("configParams", params); } } protected class RemoteBeanDefinitionDecorator implements BeanDefinitionDecorator { /** * Registers an <dwr:remote ... /> element. */ public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { Element element = (Element) node; String javascript = element.getAttribute("javascript"); BeanDefinitionBuilder beanCreator = BeanDefinitionBuilder.rootBeanDefinition(BeanCreator.class); try { String beanClassName = resolveBeanClassname(definition.getBeanDefinition(), parserContext.getRegistry()); if (beanClassName == null) { throw new FatalBeanException("Unabled to find type for beanName '" + definition.getBeanName() + "'. " + "Check your bean has a correctly configured parent or provide a class for " + " the bean definition"); } beanCreator.addPropertyValue("beanClass", ClassUtils.forName(beanClassName)); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to create DWR bean creator for '" + definition.getBeanName() + "'.", e); } String name = definition.getBeanName(); if (name.startsWith("scopedTarget.")) { name = name.substring(name.indexOf(".") + 1); } beanCreator.addPropertyValue("beanId", name); beanCreator.addPropertyValue("javascript", javascript); BeanDefinitionBuilder creatorConfig = BeanDefinitionBuilder.rootBeanDefinition(CreatorConfig.class); creatorConfig.addPropertyValue("creator", beanCreator.getBeanDefinition()); registerCreator(parserContext.getRegistry(), javascript, creatorConfig, new HashMap(), node.getChildNodes()); return definition; } /** * Try getting the beanClassName from the definition and if that fails try to get it from * the parent (and even parent BeanFactory if we have to). * * @param definition * @param registry * @return class name or null if not found */ private String resolveBeanClassname(BeanDefinition definition, BeanDefinitionRegistry registry) { String beanClassName = definition.getBeanClassName(); if (!StringUtils.hasText(beanClassName)) { while (definition instanceof ChildBeanDefinition ) { String parentName = ((ChildBeanDefinition)definition).getParentName(); BeanDefinition parentDefinition = findParentDefinition(parentName, registry); if (parentDefinition == null) { if (log.isDebugEnabled()) { log.debug("No parent bean named '" + parentName + "' could be found in the " + "hierarchy of BeanFactorys. Check you've defined a bean called '" + parentName + "'"); } break; } beanClassName = parentDefinition.getBeanClassName(); if (StringUtils.hasText(beanClassName )) { // found the class name we were looking for break; } definition = parentDefinition; } } return beanClassName; } private BeanDefinition findParentDefinition(String parentName, BeanDefinitionRegistry registry) { if (registry != null) { if (registry.containsBeanDefinition(parentName)) { return registry.getBeanDefinition(parentName); } else if (registry instanceof HierarchicalBeanFactory) { // Try to get parent definition from the parent BeanFactory. This could return null BeanFactory parentBeanFactory = ((HierarchicalBeanFactory)registry).getParentBeanFactory(); return findParentDefinition(parentName, (BeanDefinitionRegistry)parentBeanFactory); } } // we've exhausted all possibilities return null; } } protected class ConverterBeanDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { Element element = (Element) node; String type = element.getAttribute("type"); String className = element.getAttribute("class"); String javascriptClassName = element.getAttribute("javascript"); BeanDefinitionRegistry registry = parserContext.getRegistry(); ConverterConfig converterConfig = new ConverterConfig(); converterConfig.setType(type); converterConfig.setJavascriptClassName(javascriptClassName); parseConverterSettings(converterConfig, element); lookupConverters(registry).put(className, converterConfig); return definition; } } protected void parseConverterSettings(ConverterConfig converterConfig, Element parent) { NodeList children = parent.getChildNodes(); // check to see if there are any nested elements here for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.COMMENT_NODE) { continue; } Element child = (Element) node; if (child.getNodeName().equals("dwr:include")) { converterConfig.addInclude(child.getAttribute("method")); } else if (child.getNodeName().equals("dwr:exclude")) { converterConfig.addExclude(child.getAttribute("method")); } /* TODO Why is this only a property of ObjectConverter? else if (child.getNodeName().equals("dwr:force")) { converterConfig.setForce(Boolean.parseBoolean(child.getAttribute("value"))); } */ else { throw new RuntimeException("an unknown dwr:remote sub node was found: " + node.getNodeName()); } } } /** * Parse the <dwr:init> elements */ protected class InitDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node parent, BeanDefinitionHolder definition, ParserContext parserContext) { Map converters = new HashMap(); Map creators = new HashMap(); NodeList inits = parent.getChildNodes(); for (int j = 0; j < inits.getLength(); j++) { Node node = inits.item(j); if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.COMMENT_NODE) { continue; } Element child = (Element)inits.item(j); if (child.getNodeName().equals(ELEMENT_CREATOR)) { String id = child.getAttribute(ATTRIBUTE_ID); String className = child.getAttribute(ATTRIBUTE_CLASS); creators.put(id, className); } else if (child.getNodeName().equals(ELEMENT_CONVERTER)) { String id = child.getAttribute(ATTRIBUTE_ID); String className = child.getAttribute(ATTRIBUTE_CLASS); converters.put(id, className); } else { throw new RuntimeException("An unknown sub node '" + child.getNodeName() + "' was found while parsing dwr:init"); } } BeanDefinition configurator = registerSpringConfiguratorIfNecessary(parserContext.getRegistry()); configurator.getPropertyValues().addPropertyValue("creatorTypes", creators); configurator.getPropertyValues().addPropertyValue("converterTypes", converters); return definition; } } /** * Uses the BeanDefinitionDecorator since we need access to the name of the parent definition?? * Register the creatores: spring, new, null, scripted, jsf, struts, pageflow */ protected class CreatorBeanDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { Element element = (Element) node; String javascript = element.getAttribute("javascript"); String creatorType = element.getAttribute("type"); BeanDefinitionBuilder creatorConfig = BeanDefinitionBuilder.rootBeanDefinition(CreatorConfig.class); // Configure "known" creators in the CreatorConfig. If unknown then just create the configuration // and leave it up DWR itself to decide if it's a valid creator type BeanDefinitionBuilder creator; Map params = new HashMap(); if ("spring".equals(creatorType)) { // TODO Refactor so that both spring creators use the same code... BeanDefinitionBuilder springCreator = BeanDefinitionBuilder.rootBeanDefinition(BeanCreator.class); springCreator.addPropertyValue("javascript", javascript); NodeList children = element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node childNode = children.item(i); if (childNode.getNodeType() == Node.TEXT_NODE || childNode.getNodeType() == Node.COMMENT_NODE) { continue; } Element child = (Element) childNode; String paramName = child.getAttribute("name"); String value = child.getAttribute("value"); if ("beanName".equals(paramName) || "beanId".equals(paramName)) { springCreator.addPropertyValue("beanId", value); } else { params.put(paramName, value); } } creatorConfig.addPropertyValue("creator", springCreator.getBeanDefinition()); } else if ("new".equals(creatorType)) { creator = BeanDefinitionBuilder.rootBeanDefinition(NewCreator.class); creator.addPropertyValue("className", node.getAttributes().getNamedItem("class").getNodeValue()); creator.addPropertyValue("javascript", javascript); creatorConfig.addPropertyValue("creator", creator.getBeanDefinition()); } else if ("null".equals(creatorType)) { creatorConfig.addPropertyValue("creatorType", "none"); String className = element.getAttribute("class"); if (className == null || "".equals(className)) { throw new BeanInitializationException("'class' is a required attribute for the declaration "); } params.put("class", className); } else if ("pageflow".equals(creatorType)) { creatorConfig.addPropertyValue("creatorType", creatorType); } else if ("jsf".equals(creatorType) || "scripted".equals(creatorType) || "struts".equals(creatorType)) { creatorConfig.addPropertyValue("creatorType", creatorType); } else { if (log.isDebugEnabled()) { log.debug("Looking up creator type '" + creatorType + "'"); } // TODO We should delay the initialization of the creatorClass until after the bean // definitions have been parsed. BeanDefinition configurator = registerSpringConfiguratorIfNecessary(parserContext.getRegistry()); PropertyValue registeredCreators = configurator.getPropertyValues().getPropertyValue("creatorTypes"); Map registeredCreatorMap = (Map)registeredCreators.getValue(); String creatorClass = (String)registeredCreatorMap.get(creatorType); if (creatorClass == null) { // the creator type should have been registered throw new UnsupportedOperationException("Type " + creatorType + " is not supported " + " or the custom creator has not been registered dwr:init"); } else { try { Class clazz = Class.forName(creatorClass); creator = BeanDefinitionBuilder.rootBeanDefinition(clazz); creatorConfig.addPropertyValue("creator", creator.getBeanDefinition()); String className = element.getAttribute("class"); if (StringUtils.hasText(className)) { params.put("class", className); } } catch (ClassNotFoundException ex) { throw new FatalBeanException("ClassNotFoundException trying to register " + " creator '" + creatorClass + "' for javascript type '" + javascript +"'. Check the " + " class in the classpath and that the creator is register in dwr:init", ex); } } } registerCreator(parserContext.getRegistry(), javascript, creatorConfig, params, node.getChildNodes()); return definition; } } protected class SignaturesBeanDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinition config = registerSpringConfiguratorIfNecessary(registry); StringBuffer sigtext = new StringBuffer(); NodeList children = node.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeType() != Node.TEXT_NODE && child.getNodeType() != Node.CDATA_SECTION_NODE) { log.warn("Ignoring illegal node type: " + child.getNodeType()); continue; } sigtext.append(child.getNodeValue()); } config.getPropertyValues().addPropertyValue("signatures", sigtext.toString()); return definition; } } protected Map lookupCreators(BeanDefinitionRegistry registry) { BeanDefinition config = registerSpringConfiguratorIfNecessary(registry); return (Map) config.getPropertyValues().getPropertyValue("creators").getValue(); } protected Map lookupConverters(BeanDefinitionRegistry registry) { BeanDefinition config = registerSpringConfiguratorIfNecessary(registry); return (Map) config.getPropertyValues().getPropertyValue("converters").getValue(); } protected final static String DEFAULT_SPRING_CONFIGURATOR_ID = "__dwrConfiguration"; /** * The log stream */ protected static final Logger log = Logger.getLogger(DwrNamespaceHandler.class); /* * The element names */ private static final String ELEMENT_CONVERTER = "dwr:converter"; private static final String ELEMENT_CREATOR = "dwr:creator"; /* * The attribute names */ private static final String ATTRIBUTE_ID = "id"; private static final String ATTRIBUTE_CLASS = "class"; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy