KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > betwixt > digester > ElementRule


1 package org.apache.commons.betwixt.digester;
2 /*
3  * Copyright 2001-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 import java.beans.PropertyDescriptor JavaDoc;
18 import java.lang.reflect.Method JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.apache.commons.betwixt.ElementDescriptor;
22 import org.apache.commons.betwixt.XMLBeanInfo;
23 import org.apache.commons.betwixt.XMLUtils;
24 import org.apache.commons.betwixt.expression.ConstantExpression;
25 import org.apache.commons.betwixt.expression.IteratorExpression;
26 import org.apache.commons.betwixt.expression.MethodExpression;
27 import org.apache.commons.betwixt.expression.MethodUpdater;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.xml.sax.Attributes JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32
33 /**
34   * <p><code>ElementRule</code> the digester Rule for parsing
35   * the &lt;element&gt; elements.</p>
36   *
37   * @author <a HREF="mailto:jstrachan@apache.org">James Strachan</a>
38   */

39 public class ElementRule extends MappedPropertyRule {
40
41     /** Logger */
42     private static Log log = LogFactory.getLog( ElementRule.class );
43     /**
44      * Sets the log for this class
45      *
46      * @param newLog the new Log implementation for this class to use
47      * @since 0.5
48      */

49     public static final void setLog(Log newLog) {
50         log = newLog;
51     }
52
53     /** Class for which the .bewixt file is being digested */
54     private Class JavaDoc beanClass;
55     /** Base constructor */
56     public ElementRule() {}
57     
58     // Rule interface
59
//-------------------------------------------------------------------------
60

61     /**
62      * Process the beginning of this element.
63      *
64      * @param attributes The attribute list of this element
65      * @throws SAXException 1. If this tag's parent is not either an info or element tag.
66      * 2. If the name attribute is not valid XML element name.
67      * 3. If the name attribute is not present
68      * 4. If the class attribute is not a loadable (fully qualified) class name
69      */

70     public void begin(String JavaDoc name, String JavaDoc namespace, Attributes JavaDoc attributes) throws SAXException JavaDoc {
71         String JavaDoc nameAttributeValue = attributes.getValue( "name" );
72         
73         // check that the name attribute is present
74
if ( nameAttributeValue == null || nameAttributeValue.trim().equals( "" ) ) {
75             throw new SAXException JavaDoc("Name attribute is required.");
76         }
77         
78         // check that name is well formed
79
if ( !XMLUtils.isWellFormedXMLName( nameAttributeValue ) ) {
80             throw new SAXException JavaDoc("'" + nameAttributeValue + "' would not be a well formed xml element name.");
81         }
82         
83         ElementDescriptor descriptor = new ElementDescriptor();
84         descriptor.setLocalName( nameAttributeValue );
85         String JavaDoc uri = attributes.getValue( "uri" );
86         String JavaDoc qName = nameAttributeValue;
87         if ( uri != null ) {
88             descriptor.setURI( uri );
89             String JavaDoc prefix = getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri);
90             qName = prefix + ":" + nameAttributeValue;
91         }
92         descriptor.setQualifiedName( qName );
93         
94         String JavaDoc propertyName = attributes.getValue( "property" );
95         descriptor.setPropertyName( propertyName );
96         
97         String JavaDoc propertyType = attributes.getValue( "type" );
98         
99         if (log.isTraceEnabled()) {
100             log.trace(
101                     "(BEGIN) name=" + nameAttributeValue + " uri=" + uri
102                     + " property=" + propertyName + " type=" + propertyType);
103         }
104         
105         // set the property type using reflection
106
descriptor.setPropertyType(
107             getPropertyType( propertyType, beanClass, propertyName )
108         );
109         
110         String JavaDoc implementationClass = attributes.getValue( "class" );
111         if ( log.isTraceEnabled() ) {
112             log.trace("'class' attribute=" + implementationClass);
113         }
114         if ( implementationClass != null ) {
115             try {
116                 
117                 Class JavaDoc clazz = Class.forName(implementationClass);
118                 descriptor.setImplementationClass( clazz );
119                 
120             } catch (Exception JavaDoc e) {
121                 if ( log.isDebugEnabled() ) {
122                     log.debug("Cannot load class named: " + implementationClass, e);
123                 }
124                 throw new SAXException JavaDoc("Cannot load class named: " + implementationClass);
125             }
126         }
127         
128         if ( propertyName != null && propertyName.length() > 0 ) {
129             configureDescriptor(descriptor, attributes.getValue( "updater" ));
130             
131         } else {
132             String JavaDoc value = attributes.getValue( "value" );
133             if ( value != null ) {
134                 descriptor.setTextExpression( new ConstantExpression( value ) );
135             }
136         }
137         
138         Object JavaDoc top = digester.peek();
139         if ( top instanceof XMLBeanInfo ) {
140             XMLBeanInfo beanInfo = (XMLBeanInfo) top;
141             beanInfo.setElementDescriptor( descriptor );
142             beanClass = beanInfo.getBeanClass();
143             descriptor.setPropertyType( beanClass );
144             
145         } else if ( top instanceof ElementDescriptor ) {
146             ElementDescriptor parent = (ElementDescriptor) top;
147             parent.addElementDescriptor( descriptor );
148             
149         } else {
150             throw new SAXException JavaDoc( "Invalid use of <element>. It should "
151                 + "be nested inside <info> or other <element> nodes" );
152         }
153
154         digester.push(descriptor);
155     }
156
157
158     /**
159      * Process the end of this element.
160      */

161     public void end(String JavaDoc name, String JavaDoc namespace) {
162         Object JavaDoc top = digester.pop();
163     }
164
165     
166     // Implementation methods
167
//-------------------------------------------------------------------------
168

169     /**
170      * Sets the Expression and Updater from a bean property name
171      * Uses the default updater (from the standard java bean property).
172      *
173      * @param elementDescriptor configure this <code>ElementDescriptor</code>
174      * @since 0.5
175      */

176     protected void configureDescriptor(ElementDescriptor elementDescriptor) {
177         configureDescriptor( elementDescriptor, null );
178     }
179     
180     /**
181      * Sets the Expression and Updater from a bean property name
182      * Allows a custom updater to be passed in.
183      *
184      * @param elementDescriptor configure this <code>ElementDescriptor</code>
185      * @param updateMethodName custom update method. If null, then use standard
186      * @since 0.5
187      */

188     protected void configureDescriptor(
189                                         ElementDescriptor elementDescriptor,
190                                         String JavaDoc updateMethodName) {
191         Class JavaDoc beanClass = getBeanClass();
192         if ( beanClass != null ) {
193             String JavaDoc name = elementDescriptor.getPropertyName();
194             PropertyDescriptor JavaDoc descriptor =
195                 getPropertyDescriptor( beanClass, name );
196             
197             if ( descriptor != null ) {
198                 configureProperty(
199                                         elementDescriptor,
200                                         descriptor,
201                                         updateMethodName,
202                                         beanClass );
203                 
204                 getProcessedPropertyNameSet().add( name );
205             }
206         }
207     }
208     
209                                     
210     /**
211      * Configure an <code>ElementDescriptor</code> from a <code>PropertyDescriptor</code>.
212      * A custom update method may be set.
213      *
214      * @param elementDescriptor configure this <code>ElementDescriptor</code>
215      * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
216      * @param updateMethodName the name of the custom updater method to user.
217      * If null, then then
218      * @param beanClass the <code>Class</code> from which the update method should be found.
219      * This may be null only when <code>updateMethodName</code> is also null.
220      */

221     private void configureProperty(
222                                     ElementDescriptor elementDescriptor,
223                                     PropertyDescriptor JavaDoc propertyDescriptor,
224                                     String JavaDoc updateMethodName,
225                                     Class JavaDoc beanClass ) {
226         
227         Class JavaDoc type = propertyDescriptor.getPropertyType();
228         Method JavaDoc readMethod = propertyDescriptor.getReadMethod();
229         Method JavaDoc writeMethod = propertyDescriptor.getWriteMethod();
230         
231         String JavaDoc existingLocalName = elementDescriptor.getLocalName();
232         if (existingLocalName == null || "".equals(existingLocalName)) {
233             elementDescriptor.setLocalName( propertyDescriptor.getName() );
234         }
235         elementDescriptor.setPropertyType( type );
236         
237         // TODO: associate more bean information with the descriptor?
238
//nodeDescriptor.setDisplayName( propertyDescriptor.getDisplayName() );
239
//nodeDescriptor.setShortDescription( propertyDescriptor.getShortDescription() );
240

241         if ( readMethod == null ) {
242             log.trace( "No read method" );
243             return;
244         }
245         
246         if ( log.isTraceEnabled() ) {
247             log.trace( "Read method=" + readMethod.getName() );
248         }
249         
250         // choose response from property type
251

252         // TODO: ignore class property ??
253
if ( Class JavaDoc.class.equals( type ) && "class".equals( propertyDescriptor.getName() ) ) {
254             log.trace( "Ignoring class property" );
255             return;
256         }
257         if ( getXMLIntrospector().isPrimitiveType( type ) ) {
258             elementDescriptor.setTextExpression( new MethodExpression( readMethod ) );
259             
260         } else if ( getXMLIntrospector().isLoopType( type ) ) {
261             log.trace("Loop type ??");
262             
263             // don't wrap this in an extra element as its specified in the
264
// XML descriptor so no need.
265
elementDescriptor.setContextExpression(
266                 new IteratorExpression( new MethodExpression( readMethod ) )
267             );
268             elementDescriptor.setHollow(true);
269
270             writeMethod = null;
271             
272             if (Map JavaDoc.class.isAssignableFrom(type)) {
273                 elementDescriptor.setLocalName( "entry" );
274                 // add elements for reading
275
ElementDescriptor keyDescriptor = new ElementDescriptor( "key" );
276                 keyDescriptor.setHollow( true );
277                 elementDescriptor.addElementDescriptor( keyDescriptor );
278             
279                 ElementDescriptor valueDescriptor = new ElementDescriptor( "value" );
280                 valueDescriptor.setHollow( true );
281                 elementDescriptor.addElementDescriptor( valueDescriptor );
282             }
283             
284         } else {
285             log.trace( "Standard property" );
286             elementDescriptor.setHollow(true);
287             elementDescriptor.setContextExpression( new MethodExpression( readMethod ) );
288         }
289     
290         // see if we have a custom method update name
291
if (updateMethodName == null) {
292             // set standard write method
293
if ( writeMethod != null ) {
294                 elementDescriptor.setUpdater( new MethodUpdater( writeMethod ) );
295             }
296             
297         } else {
298             // see if we can find and set the custom method
299
if ( log.isTraceEnabled() ) {
300                 log.trace( "Finding custom method: " );
301                 log.trace( " on:" + beanClass );
302                 log.trace( " name:" + updateMethodName );
303             }
304             
305             Method JavaDoc updateMethod = null;
306             Method JavaDoc[] methods = beanClass.getMethods();
307             for ( int i = 0, size = methods.length; i < size; i++ ) {
308                 Method JavaDoc method = methods[i];
309                 if ( updateMethodName.equals( method.getName() ) ) {
310                     // we have a matching name
311
// check paramters are correct
312
if (methods[i].getParameterTypes().length == 1) {
313                         // we'll use first match
314
updateMethod = methods[i];
315                         if ( log.isTraceEnabled() ) {
316                             log.trace("Matched method:" + updateMethod);
317                         }
318                         // done since we're using the first match
319
break;
320                     }
321                 }
322             }
323             
324             if (updateMethod == null) {
325                 if ( log.isInfoEnabled() ) {
326                     
327                     log.info("No method with name '" + updateMethodName + "' found for update");
328                 }
329             } else {
330     
331                 elementDescriptor.setUpdater( new MethodUpdater( updateMethod ) );
332                 elementDescriptor.setSingularPropertyType( updateMethod.getParameterTypes()[0] );
333                 if ( log.isTraceEnabled() ) {
334                     log.trace( "Set custom updater on " + elementDescriptor);
335                 }
336             }
337         }
338     }
339 }
340
Popular Tags