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