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 }