1 package org.apache.commons.betwixt.digester;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.beans.BeanInfo;
20 import java.beans.Introspector;
21 import java.beans.PropertyDescriptor;
22 import java.lang.reflect.Method;
23
24 import org.apache.commons.betwixt.AttributeDescriptor;
25 import org.apache.commons.betwixt.ElementDescriptor;
26 import org.apache.commons.betwixt.XMLUtils;
27 import org.apache.commons.betwixt.expression.ConstantExpression;
28 import org.apache.commons.betwixt.expression.MethodExpression;
29 import org.apache.commons.betwixt.expression.MethodUpdater;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.xml.sax.Attributes;
33 import org.xml.sax.SAXException;
34
35 /***
36 * <p><code>AttributeRule</code> the digester Rule for parsing the
37 * <attribute> elements.</p>
38 *
39 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
40 * @version $Id: AttributeRule.java 438373 2006-08-30 05:17:21Z bayard $
41 */
42 public class AttributeRule extends RuleSupport {
43
44 /*** Logger */
45 private static final Log log = LogFactory.getLog( AttributeRule.class );
46 /*** This loads all classes created by name. Defaults to this class's classloader */
47 private ClassLoader classLoader;
48 /*** The <code>Class</code> whose .betwixt file is being digested */
49 private Class beanClass;
50
51 /*** Base constructor */
52 public AttributeRule() {
53 this.classLoader = getClass().getClassLoader();
54 }
55
56
57
58
59 /***
60 * Process the beginning of this element.
61 *
62 * @param attributes The attribute list of this element
63 * @throws SAXException 1. If the attribute tag is not inside an element tag.
64 * 2. If the name attribute is not valid XML attribute name.
65 */
66 public void begin(String name, String namespace, Attributes attributes) throws SAXException {
67
68 AttributeDescriptor descriptor = new AttributeDescriptor();
69 String nameAttributeValue = attributes.getValue( "name" );
70
71
72 if ( !XMLUtils.isWellFormedXMLName( nameAttributeValue ) ) {
73 throw new SAXException("'" + nameAttributeValue + "' would not be a well formed xml attribute name.");
74 }
75
76 String qName = nameAttributeValue;
77 descriptor.setLocalName( nameAttributeValue );
78 String uri = attributes.getValue( "uri" );
79 if ( uri != null ) {
80 descriptor.setURI( uri );
81 String prefix = getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri);
82 qName = prefix + ":" + nameAttributeValue;
83 }
84 descriptor.setQualifiedName( qName );
85
86 String propertyName = attributes.getValue( "property" );
87 descriptor.setPropertyName( propertyName );
88 descriptor.setPropertyType( loadClass( attributes.getValue( "type" ) ) );
89
90 if ( propertyName != null && propertyName.length() > 0 ) {
91 configureDescriptor(descriptor);
92 } else {
93 String value = attributes.getValue( "value" );
94 if ( value != null ) {
95 descriptor.setTextExpression( new ConstantExpression( value ) );
96 }
97 }
98
99 Object top = digester.peek();
100 if ( top instanceof ElementDescriptor ) {
101 ElementDescriptor parent = (ElementDescriptor) top;
102 parent.addAttributeDescriptor( descriptor );
103 } else {
104 throw new SAXException( "Invalid use of <attribute>. It should "
105 + "be nested inside an <element> element" );
106 }
107
108 digester.push(descriptor);
109 }
110
111
112 /***
113 * Process the end of this element.
114 */
115 public void end(String name, String namespace) {
116 AttributeDescriptor descriptor = (AttributeDescriptor)digester.pop();
117 ElementDescriptor parent = (ElementDescriptor)digester.peek();
118
119
120 if( getXMLIntrospector().getConfiguration().getAttributeSuppressionStrategy().suppress(descriptor)) {
121 parent.removeAttributeDescriptor(descriptor);
122 }
123 }
124
125
126
127
128 /***
129 * Loads a class (using the appropriate classloader)
130 *
131 * @param name the name of the class to load
132 * @return the class instance loaded by the appropriate classloader
133 */
134 protected Class loadClass( String name ) {
135
136 if ( name != null ) {
137 try {
138 return classLoader.loadClass(name);
139 } catch (Exception e) {
140 }
141 }
142 return null;
143 }
144
145 /***
146 * Set the Expression and Updater from a bean property name
147 * @param attributeDescriptor configure this <code>AttributeDescriptor</code>
148 * from the property with a matching name in the bean class
149 */
150 protected void configureDescriptor(AttributeDescriptor attributeDescriptor) {
151 Class beanClass = getBeanClass();
152 if ( beanClass != null ) {
153 String name = attributeDescriptor.getPropertyName();
154 try {
155 BeanInfo beanInfo;
156 if( getXMLIntrospector().getConfiguration().ignoreAllBeanInfo() ) {
157 beanInfo = Introspector.getBeanInfo( beanClass, Introspector.IGNORE_ALL_BEANINFO );
158 }
159 else {
160 beanInfo = Introspector.getBeanInfo( beanClass );
161 }
162 PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
163 if ( descriptors != null ) {
164 for ( int i = 0, size = descriptors.length; i < size; i++ ) {
165 PropertyDescriptor descriptor = descriptors[i];
166 if ( name.equals( descriptor.getName() ) ) {
167 configureProperty( attributeDescriptor, descriptor );
168 getProcessedPropertyNameSet().add( name );
169 break;
170 }
171 }
172 }
173 } catch (Exception e) {
174 log.warn( "Caught introspection exception", e );
175 }
176 }
177 }
178
179 /***
180 * Configure an <code>AttributeDescriptor</code> from a <code>PropertyDescriptor</code>
181 *
182 * @param attributeDescriptor configure this <code>AttributeDescriptor</code>
183 * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
184 */
185 private void configureProperty(
186 AttributeDescriptor attributeDescriptor,
187 PropertyDescriptor propertyDescriptor ) {
188 Class type = propertyDescriptor.getPropertyType();
189 Method readMethod = propertyDescriptor.getReadMethod();
190 Method writeMethod = propertyDescriptor.getWriteMethod();
191
192 if ( readMethod == null ) {
193 log.trace( "No read method" );
194 return;
195 }
196
197 if ( log.isTraceEnabled() ) {
198 log.trace( "Read method=" + readMethod );
199 }
200
201
202 if ( getXMLIntrospector().isLoopType( type ) ) {
203 log.warn( "Using loop type for an attribute. Type = "
204 + type.getName() + " attribute: " + attributeDescriptor.getQualifiedName() );
205 }
206
207 log.trace( "Standard property" );
208 attributeDescriptor.setTextExpression( new MethodExpression( readMethod ) );
209
210 if ( writeMethod != null ) {
211 attributeDescriptor.setUpdater( new MethodUpdater( writeMethod ) );
212 }
213
214 attributeDescriptor.setPropertyName( propertyDescriptor.getName() );
215 attributeDescriptor.setPropertyType( type );
216
217
218
219
220 }
221
222 }