001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.spring.handler; 018 019 import org.w3c.dom.Attr; 020 import org.w3c.dom.Element; 021 import org.w3c.dom.NamedNodeMap; 022 023 import org.springframework.beans.factory.support.BeanDefinitionBuilder; 024 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; 025 import org.springframework.core.Conventions; 026 import org.springframework.util.Assert; 027 import org.springframework.util.StringUtils; 028 029 /** 030 * A base class for a parser for a bean. 031 * 032 * @version $Revision: 927682 $ 033 */ 034 // TODO cannot use AbstractSimpleBeanDefinitionParser 035 // as doParse() is final and isEligableAttribute does not allow us to filter out attributes 036 // with the name "xmlns:" 037 public class BeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 038 private Class type; 039 040 public BeanDefinitionParser(Class type) { 041 this.type = type; 042 } 043 044 protected Class getBeanClass(Element element) { 045 return type; 046 } 047 048 protected boolean isEligibleAttribute(String attributeName) { 049 return attributeName != null && !ID_ATTRIBUTE.equals(attributeName) 050 && !attributeName.equals("xmlns") && !attributeName.startsWith("xmlns:"); 051 } 052 053 // TODO the following code is copied from AbstractSimpleBeanDefinitionParser 054 // it can be removed if ever the doParse() method is not final! 055 // or the Spring bug http://jira.springframework.org/browse/SPR-4599 is resolved 056 057 /** 058 * Parse the supplied {@link Element} and populate the supplied 059 * {@link BeanDefinitionBuilder} as required. 060 * <p>This implementation maps any attributes present on the 061 * supplied element to {@link org.springframework.beans.PropertyValue} 062 * instances, and 063 * {@link BeanDefinitionBuilder#addPropertyValue(String, Object) adds them} 064 * to the 065 * {@link org.springframework.beans.factory.config.BeanDefinition builder}. 066 * <p>The {@link #extractPropertyName(String)} method is used to 067 * reconcile the name of an attribute with the name of a JavaBean 068 * property. 069 * 070 * @param element the XML element being parsed 071 * @param builder used to define the <code>BeanDefinition</code> 072 * @see #extractPropertyName(String) 073 */ 074 protected final void doParse(Element element, BeanDefinitionBuilder builder) { 075 NamedNodeMap attributes = element.getAttributes(); 076 for (int x = 0; x < attributes.getLength(); x++) { 077 Attr attribute = (Attr) attributes.item(x); 078 String name = attribute.getLocalName(); 079 String fullName = attribute.getName(); 080 if (!fullName.startsWith("xmlns:") && !fullName.equals("xmlns") && isEligibleAttribute(name)) { 081 String propertyName = extractPropertyName(name); 082 Assert.state(StringUtils.hasText(propertyName), 083 "Illegal property name returned from 'extractPropertyName(String)': cannot be null or empty."); 084 builder.addPropertyValue(propertyName, attribute.getValue()); 085 } 086 } 087 postProcess(builder, element); 088 } 089 090 091 /** 092 * Extract a JavaBean property name from the supplied attribute name. 093 * <p>The default implementation uses the 094 * {@link Conventions#attributeNameToPropertyName(String)} 095 * method to perform the extraction. 096 * <p>The name returned must obey the standard JavaBean property name 097 * conventions. For example for a class with a setter method 098 * '<code>setBingoHallFavourite(String)</code>', the name returned had 099 * better be '<code>bingoHallFavourite</code>' (with that exact casing). 100 * 101 * @param attributeName the attribute name taken straight from the 102 * XML element being parsed (never <code>null</code>) 103 * @return the extracted JavaBean property name (must never be <code>null</code>) 104 */ 105 protected String extractPropertyName(String attributeName) { 106 return Conventions.attributeNameToPropertyName(attributeName); 107 } 108 109 /** 110 * Hook method that derived classes can implement to inspect/change a 111 * bean definition after parsing is complete. 112 * <p>The default implementation does nothing. 113 * 114 * @param beanDefinition the parsed (and probably totally defined) bean definition being built 115 * @param element the XML element that was the source of the bean definition's metadata 116 */ 117 protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) { 118 } 119 120 }