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 /** 031 * A base class for a parser for a bean. 032 * 033 * @version $Revision: 747759 $ 034 */ 035 // TODO cannot use AbstractSimpleBeanDefinitionParser 036 // as doParse() is final and isEligableAttribute does not allow us to filter out attributes 037 // with the name "xmlns:" 038 public class BeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 039 private Class type; 040 041 protected BeanDefinitionParser() { 042 } 043 044 public BeanDefinitionParser(Class type) { 045 this.type = type; 046 } 047 048 protected Class getBeanClass(Element element) { 049 if (type == null) { 050 type = loadType(); 051 } 052 return type; 053 } 054 055 protected Class loadType() { 056 throw new IllegalArgumentException("No type specified!"); 057 } 058 059 protected boolean isEligibleAttribute(String attributeName) { 060 return attributeName != null && !ID_ATTRIBUTE.equals(attributeName) 061 && !attributeName.equals("xmlns") && !attributeName.startsWith("xmlns:"); 062 } 063 064 // TODO the following code is copied from AbstractSimpleBeanDefinitionParser 065 // it can be removed if ever the doParse() method is not final! 066 // or the Spring bug http://jira.springframework.org/browse/SPR-4599 is resolved 067 068 /** 069 * Parse the supplied {@link Element} and populate the supplied 070 * {@link BeanDefinitionBuilder} as required. 071 * <p>This implementation maps any attributes present on the 072 * supplied element to {@link org.springframework.beans.PropertyValue} 073 * instances, and 074 * {@link BeanDefinitionBuilder#addPropertyValue(String, Object) adds them} 075 * to the 076 * {@link org.springframework.beans.factory.config.BeanDefinition builder}. 077 * <p>The {@link #extractPropertyName(String)} method is used to 078 * reconcile the name of an attribute with the name of a JavaBean 079 * property. 080 * 081 * @param element the XML element being parsed 082 * @param builder used to define the <code>BeanDefinition</code> 083 * @see #extractPropertyName(String) 084 */ 085 protected final void doParse(Element element, BeanDefinitionBuilder builder) { 086 NamedNodeMap attributes = element.getAttributes(); 087 for (int x = 0; x < attributes.getLength(); x++) { 088 Attr attribute = (Attr) attributes.item(x); 089 String name = attribute.getLocalName(); 090 String fullName = attribute.getName(); 091 if (!fullName.startsWith("xmlns:") && !fullName.equals("xmlns") && isEligibleAttribute(name)) { 092 String propertyName = extractPropertyName(name); 093 Assert.state(StringUtils.hasText(propertyName), 094 "Illegal property name returned from 'extractPropertyName(String)': cannot be null or empty."); 095 builder.addPropertyValue(propertyName, attribute.getValue()); 096 } 097 } 098 postProcess(builder, element); 099 } 100 101 102 /** 103 * Extract a JavaBean property name from the supplied attribute name. 104 * <p>The default implementation uses the 105 * {@link Conventions#attributeNameToPropertyName(String)} 106 * method to perform the extraction. 107 * <p>The name returned must obey the standard JavaBean property name 108 * conventions. For example for a class with a setter method 109 * '<code>setBingoHallFavourite(String)</code>', the name returned had 110 * better be '<code>bingoHallFavourite</code>' (with that exact casing). 111 * 112 * @param attributeName the attribute name taken straight from the 113 * XML element being parsed (never <code>null</code>) 114 * @return the extracted JavaBean property name (must never be <code>null</code>) 115 */ 116 protected String extractPropertyName(String attributeName) { 117 return Conventions.attributeNameToPropertyName(attributeName); 118 } 119 120 /** 121 * Hook method that derived classes can implement to inspect/change a 122 * bean definition after parsing is complete. 123 * <p>The default implementation does nothing. 124 * 125 * @param beanDefinition the parsed (and probably totally defined) bean definition being built 126 * @param element the XML element that was the source of the bean definition's metadata 127 */ 128 protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) { 129 } 130 131 }