001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022package org.granite.spring; 023 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.springframework.beans.factory.config.BeanDefinition; 029import org.springframework.beans.factory.parsing.BeanComponentDefinition; 030import org.springframework.beans.factory.parsing.CompositeComponentDefinition; 031import org.springframework.beans.factory.support.BeanDefinitionBuilder; 032import org.springframework.beans.factory.support.ManagedList; 033import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; 034import org.springframework.beans.factory.xml.ParserContext; 035import org.springframework.core.Conventions; 036import org.springframework.util.StringUtils; 037import org.springframework.util.xml.DomUtils; 038import org.w3c.dom.Element; 039 040/** 041 * @author William Drai 042 */ 043public class ServerFilterBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 044 045 private static final String SERVER_FILTER_BEAN_NAME = "org.granite.spring.ServerFilter"; 046 047 private static final String GRANITE_CONFIG_BEAN_NAME = "org.granite.spring.SpringGraniteConfig"; 048 049 public static final String GRAVITY_FACTORY_BEAN_NAME = "org.granite.spring.gravityFactory"; 050 051 private static final String DEFAULT_HANDLER_MAPPING_CLASS_NAME = "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"; 052 053 054 @Override 055 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 056 CompositeComponentDefinition componentDefinition = new CompositeComponentDefinition(element.getLocalName(), 057 parserContext.extractSource(element)); 058 parserContext.pushContainingComponent(componentDefinition); 059 060 element.setAttribute(ID_ATTRIBUTE, SERVER_FILTER_BEAN_NAME); 061 062 mapOptionalAttributes(element, parserContext, builder, "tide", "type", "useLong", "useBigDecimal", "useBigInteger"); 063 064 Object source = parserContext.extractSource(element); 065 066 ManagedList<String> roles = new ManagedList<String>(); 067 roles.setSource(source); 068 List<Element> rolesElements = DomUtils.getChildElementsByTagName(element, "tide-roles"); 069 for (Element rolesElement : rolesElements) { 070 List<Element> valueElements = DomUtils.getChildElementsByTagName(rolesElement, "value"); 071 for (Element valueElement : valueElements) 072 roles.add(valueElement.getTextContent()); 073 } 074 if (!roles.isEmpty()) 075 builder.addPropertyValue("tideRoles", roles); 076 077 ManagedList<String> tideAnnotations = new ManagedList<String>(); 078 tideAnnotations.setSource(source); 079 List<Element> tideAnnotationsElements = DomUtils.getChildElementsByTagName(element, "tide-annotations"); 080 for (Element tideAnnotationsElement : tideAnnotationsElements) { 081 List<Element> valueElements = DomUtils.getChildElementsByTagName(tideAnnotationsElement, "value"); 082 for (Element valueElement : valueElements) 083 tideAnnotations.add(valueElement.getTextContent()); 084 } 085 builder.addPropertyValue("tideAnnotations", tideAnnotations); 086 087 ManagedList<String> tideInterfaces = new ManagedList<String>(); 088 tideInterfaces.setSource(source); 089 List<Element> tideInterfacesElements = DomUtils.getChildElementsByTagName(element, "tide-interfaces"); 090 for (Element tideInterfacesElement : tideInterfacesElements) { 091 List<Element> valueElements = DomUtils.getChildElementsByTagName(tideInterfacesElement, "value"); 092 for (Element valueElement : valueElements) 093 tideInterfaces.add(valueElement.getTextContent()); 094 } 095 builder.addPropertyValue("tideInterfaces", tideInterfaces); 096 097 ManagedList<String> tideNames = new ManagedList<String>(); 098 tideNames.setSource(source); 099 List<Element> tideNamesElements = DomUtils.getChildElementsByTagName(element, "tide-names"); 100 for (Element tideNamesElement : tideNamesElements) { 101 List<Element> valueElements = DomUtils.getChildElementsByTagName(tideNamesElement, "value"); 102 for (Element valueElement : valueElements) 103 tideNames.add(valueElement.getTextContent()); 104 } 105 builder.addPropertyValue("tideNames", tideNames); 106 107 ManagedList<String> tideTypes = new ManagedList<String>(); 108 tideTypes.setSource(source); 109 List<Element> tideTypesElements = DomUtils.getChildElementsByTagName(element, "tide-types"); 110 for (Element tideTypesElement : tideTypesElements) { 111 List<Element> valueElements = DomUtils.getChildElementsByTagName(tideTypesElement, "value"); 112 for (Element valueElement : valueElements) 113 tideTypes.add(valueElement.getTextContent()); 114 } 115 builder.addPropertyValue("tideTypes", tideTypes); 116 117 ManagedList<String> exceptionConverters = new ManagedList<String>(); 118 exceptionConverters.setSource(source); 119 List<Element> exceptionConvertersElements = DomUtils.getChildElementsByTagName(element, "exception-converters"); 120 for (Element exceptionConvertersElement : exceptionConvertersElements) { 121 List<Element> valueElements = DomUtils.getChildElementsByTagName(exceptionConvertersElement, "value"); 122 for (Element valueElement : valueElements) 123 exceptionConverters.add(valueElement.getTextContent()); 124 } 125 builder.addPropertyValue("exceptionConverters", exceptionConverters); 126 127 Element amf3MessageInterceptor = DomUtils.getChildElementByTagName(element, "amf3-message-interceptor"); 128 if (amf3MessageInterceptor != null) 129 builder.addPropertyReference("amf3MessageInterceptor", amf3MessageInterceptor.getTextContent()); 130 131 configureGraniteDS(element, parserContext, DomUtils.getChildElementByTagName(element, "granite-config")); 132 133 registerHandlerMappings(element, parserContext, element.getAttribute("url-pattern")); 134 135 parserContext.popAndRegisterContainingComponent(); 136 } 137 138 @Override 139 protected String getBeanClassName(Element element) { 140 return ServerFilter.class.getName(); 141 } 142 143 private void configureGraniteDS(Element parent, ParserContext parserContext, Element graniteConfigElement) { 144 if (parserContext.getRegistry().containsBeanDefinition(GRANITE_CONFIG_BEAN_NAME)) 145 return; 146 147 Element source = graniteConfigElement != null ? graniteConfigElement : parent; 148 149 BeanDefinitionBuilder graniteConfigBuilder = BeanDefinitionBuilder.genericBeanDefinition(SpringGraniteConfig.class); 150 registerInfrastructureComponent(source, parserContext, graniteConfigBuilder, GRANITE_CONFIG_BEAN_NAME); 151 152 BeanDefinitionBuilder gravityFactoryBuilder = BeanDefinitionBuilder.rootBeanDefinition(SpringGravityFactoryBean.class); 153 registerInfrastructureComponent(source, parserContext, gravityFactoryBuilder, GRAVITY_FACTORY_BEAN_NAME); 154 } 155 156 @SuppressWarnings({ "unchecked", "rawtypes" }) 157 private void registerHandlerMappings(Element parent, ParserContext parserContext, String urlPattern) { 158 BeanDefinitionBuilder handlerMappingBuilder = BeanDefinitionBuilder.genericBeanDefinition(DEFAULT_HANDLER_MAPPING_CLASS_NAME); 159 160 Map mappings = new HashMap(); 161 if (urlPattern != null) 162 mappings.put(urlPattern, parent.getAttribute(ID_ATTRIBUTE)); 163 164 handlerMappingBuilder.addPropertyValue("urlMap", mappings); 165 registerInfrastructureComponent(parent, parserContext, handlerMappingBuilder, 166 parent.getAttribute(ID_ATTRIBUTE) + "_handlerMapping"); 167 } 168 169 170 // From Spring-Flex 171 172 static void registerInfrastructureComponent(Element element, ParserContext parserContext, BeanDefinitionBuilder componentBuilder, String beanName) { 173 componentBuilder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); 174 componentBuilder.getRawBeanDefinition().setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 175 parserContext.registerBeanComponent(new BeanComponentDefinition(componentBuilder.getBeanDefinition(), beanName)); 176 } 177 178 static void mapOptionalAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, String... attrs) { 179 for (String attr : attrs) { 180 String value = element.getAttribute(attr); 181 if (StringUtils.hasText(value)) { 182 String propertyName = Conventions.attributeNameToPropertyName(attr); 183 if (validateProperty(element, parserContext, propertyName, attr)) { 184 builder.addPropertyValue(propertyName, value); 185 } 186 } 187 } 188 } 189 190 private static boolean validateProperty(Element element, ParserContext parserContext, String propertyName, String attr) { 191 if (!StringUtils.hasText(propertyName)) { 192 parserContext.getReaderContext().error( 193 "Illegal property name trying to convert from attribute '" + attr + "' : cannot be null or empty.", 194 parserContext.extractSource(element)); 195 return false; 196 } 197 return true; 198 } 199}