KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > betwixt > BeanProperty


1 package org.apache.commons.betwixt;
2
3 /*
4  * Copyright 2001-2004 The Apache Software Foundation.
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
18 import java.beans.PropertyDescriptor JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import org.apache.commons.beanutils.DynaProperty;
23 import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
24 import org.apache.commons.betwixt.expression.DynaBeanExpression;
25 import org.apache.commons.betwixt.expression.Expression;
26 import org.apache.commons.betwixt.expression.IteratorExpression;
27 import org.apache.commons.betwixt.expression.MethodExpression;
28 import org.apache.commons.betwixt.expression.MethodUpdater;
29 import org.apache.commons.betwixt.expression.Updater;
30 import org.apache.commons.betwixt.strategy.NameMapper;
31 import org.apache.commons.betwixt.strategy.SimpleTypeMapper;
32 import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
33 import org.apache.commons.logging.Log;
34
35 /**
36   * Betwixt-centric view of a bean (or pseudo-bean) property.
37   * This object decouples the way that the (possibly pseudo) property introspection
38   * is performed from the results of that introspection.
39   *
40   * @author Robert Burrell Donkin
41   * @since 0.5
42   */

43 public class BeanProperty {
44
45     /** The bean name for the property (not null) */
46     private final String JavaDoc propertyName;
47     /** The type of this property (not null) */
48     private final Class JavaDoc propertyType;
49     /** The Expression used to read values of this property (possibly null) */
50     private Expression propertyExpression;
51     /** The Updater used to write values of this property (possibly null) */
52     private Updater propertyUpdater;
53
54     /**
55      * Construct a BeanProperty.
56      * @param propertyName not null
57      * @param propertyType not null
58      * @param propertyExpression the Expression used to read the property,
59      * null if the property is not readable
60      * @param propertyUpdater the Updater used to write the property,
61      * null if the property is not writable
62      */

63     public BeanProperty (
64                         String JavaDoc propertyName,
65                         Class JavaDoc propertyType,
66                         Expression propertyExpression,
67                         Updater propertyUpdater) {
68         this.propertyName = propertyName;
69         this.propertyType = propertyType;
70         this.propertyExpression = propertyExpression;
71         this.propertyUpdater = propertyUpdater;
72     }
73     
74     /**
75      * Constructs a BeanProperty from a <code>PropertyDescriptor</code>.
76      * @param descriptor not null
77      */

78     public BeanProperty(PropertyDescriptor JavaDoc descriptor) {
79         this.propertyName = descriptor.getName();
80         this.propertyType = descriptor.getPropertyType();
81         
82         Method JavaDoc readMethod = descriptor.getReadMethod();
83         if ( readMethod != null ) {
84             this.propertyExpression = new MethodExpression( readMethod );
85         }
86         
87         Method JavaDoc writeMethod = descriptor.getWriteMethod();
88         if ( writeMethod != null ) {
89             this.propertyUpdater = new MethodUpdater( writeMethod );
90         }
91     }
92     
93     /**
94      * Constructs a BeanProperty from a <code>DynaProperty</code>
95      * @param dynaProperty not null
96      */

97     public BeanProperty(DynaProperty dynaProperty) {
98         this.propertyName = dynaProperty.getName();
99         this.propertyType = dynaProperty.getType();
100         this.propertyExpression = new DynaBeanExpression( propertyName );
101         // todo: add updater
102
}
103
104     /**
105       * Gets the bean name for this property.
106       * Betwixt will map this to an xml name.
107       * @return the bean name for this property, not null
108       */

109     public String JavaDoc getPropertyName() {
110         return propertyName;
111     }
112
113     /**
114       * Gets the type of this property.
115       * @return the property type, not null
116       */

117     public Class JavaDoc getPropertyType() {
118         return propertyType;
119     }
120     
121     /**
122       * Gets the expression used to read this property.
123       * @return the expression to be used to read this property
124       * or null if this property is not readable.
125       */

126     public Expression getPropertyExpression() {
127         return propertyExpression;
128     }
129     
130     /**
131       * Gets the updater used to write to this properyty.
132       * @return the Updater to the used to write to this property
133       * or null if this property is not writable.
134       */

135     public Updater getPropertyUpdater() {
136         return propertyUpdater;
137     }
138     
139     /**
140      * Create a XML descriptor from a bean one.
141      * Go through and work out whether it's a loop property, a primitive or a standard.
142      * The class property is ignored.
143      *
144      * @param beanProperty the BeanProperty specifying the property
145      * @return a correctly configured <code>NodeDescriptor</code> for the property
146      */

147     public Descriptor createXMLDescriptor( IntrospectionConfiguration configuration ) {
148         Log log = configuration.getIntrospectionLog();
149         if (log.isTraceEnabled()) {
150             log.trace("Creating descriptor for property: name="
151                 + getPropertyName() + " type=" + getPropertyType());
152         }
153         
154         NodeDescriptor descriptor = null;
155         Expression propertyExpression = getPropertyExpression();
156         Updater propertyUpdater = getPropertyUpdater();
157         
158         if ( propertyExpression == null ) {
159             if (log.isTraceEnabled()) {
160                 log.trace( "No read method for property: name="
161                     + getPropertyName() + " type=" + getPropertyType());
162             }
163             return null;
164         }
165         
166         if ( log.isTraceEnabled() ) {
167             log.trace( "Property expression=" + propertyExpression );
168         }
169         
170         // choose response from property type
171

172         // XXX: ignore class property ??
173
if ( Class JavaDoc.class.equals( getPropertyType() ) && "class".equals( getPropertyName() ) ) {
174             log.trace( "Ignoring class property" );
175             return null;
176             
177         }
178         
179         //TODO this big conditional should be replaced with subclasses based
180
// on the type
181

182         //TODO complete simple type implementation
183
TypeBindingStrategy.BindingType bindingType
184                 = configuration.getTypeBindingStrategy().bindingType( getPropertyType() ) ;
185         if ( bindingType.equals( TypeBindingStrategy.BindingType.PRIMITIVE ) ) {
186             descriptor =
187                 createDescriptorForPrimitive(
188                     configuration,
189                     propertyExpression,
190                     propertyUpdater);
191             
192         } else if ( XMLIntrospectorHelper.isLoopType( getPropertyType() ) ) {
193             
194             if (log.isTraceEnabled()) {
195                 log.trace("Loop type: " + getPropertyName());
196                 log.trace("Wrap in collections? " + configuration.isWrapCollectionsInElement());
197             }
198             
199             if ( Map JavaDoc.class.isAssignableFrom( getPropertyType() )) {
200                 descriptor = createDescriptorForMap( configuration, propertyExpression );
201             } else {
202             
203                 descriptor
204                     = createDescriptorForCollective( configuration, propertyUpdater, propertyExpression );
205             }
206         } else {
207             if (log.isTraceEnabled()) {
208                 log.trace( "Standard property: " + getPropertyName());
209             }
210             descriptor =
211                 createDescriptorForStandard(
212                     propertyExpression,
213                     propertyUpdater,
214                     configuration);
215         }
216         
217         
218        
219         if (log.isTraceEnabled()) {
220             log.trace( "Created descriptor:" );
221             log.trace( descriptor );
222         }
223         return descriptor;
224     }
225
226     /**
227      * Configures descriptor (in the standard way).
228      * This sets the common properties.
229      *
230      * @param propertyName the name of the property mapped to the Descriptor, not null
231      * @param propertyType the type of the property mapped to the Descriptor, not null
232      * @param descriptor Descriptor to map, not null
233      * @param configuration IntrospectionConfiguration, not null
234      */

235     private void configureDescriptor(
236         NodeDescriptor descriptor,
237         IntrospectionConfiguration configuration) {
238         NameMapper nameMapper = configuration.getElementNameMapper();
239         if (descriptor instanceof AttributeDescriptor) {
240             // we want to use the attributemapper only when it is an attribute..
241
nameMapper = configuration.getAttributeNameMapper();
242         
243         }
244         descriptor.setLocalName( nameMapper.mapTypeToElementName( propertyName ));
245         descriptor.setPropertyName( getPropertyName() );
246         descriptor.setPropertyType( getPropertyType() );
247     }
248     
249     /**
250      * Creates an <code>ElementDescriptor</code> for a standard property
251      * @param propertyExpression
252      * @param propertyUpdater
253      * @return
254      */

255     private ElementDescriptor createDescriptorForStandard(
256         Expression propertyExpression,
257         Updater propertyUpdater,
258         IntrospectionConfiguration configuration) {
259             
260         ElementDescriptor result;
261
262         ElementDescriptor elementDescriptor = new ElementDescriptor();
263         elementDescriptor.setContextExpression( propertyExpression );
264         if ( propertyUpdater != null ) {
265             elementDescriptor.setUpdater( propertyUpdater );
266         }
267         
268         elementDescriptor.setHollow(true);
269         
270         result = elementDescriptor;
271         
272         configureDescriptor(result, configuration);
273         return result;
274     }
275
276     /**
277      * Creates an ElementDescriptor for an <code>Map</code> type property
278      * @param configuration
279      * @param propertyExpression
280      * @return
281      */

282     private ElementDescriptor createDescriptorForMap(
283         IntrospectionConfiguration configuration,
284         Expression propertyExpression) {
285             
286         //TODO: need to clean the element descriptors so that the wrappers are plain
287
ElementDescriptor result;
288         
289         ElementDescriptor entryDescriptor = new ElementDescriptor();
290         entryDescriptor.setContextExpression(
291             new IteratorExpression( propertyExpression )
292         );
293
294         entryDescriptor.setLocalName( "entry" );
295         entryDescriptor.setPropertyName( getPropertyName() );
296         entryDescriptor.setPropertyType( getPropertyType() );
297         
298         // add elements for reading
299
ElementDescriptor keyDescriptor = new ElementDescriptor( "key" );
300         keyDescriptor.setHollow( true );
301         entryDescriptor.addElementDescriptor( keyDescriptor );
302         
303         ElementDescriptor valueDescriptor = new ElementDescriptor( "value" );
304         valueDescriptor.setHollow( true );
305         entryDescriptor.addElementDescriptor( valueDescriptor );
306         
307         
308         if ( configuration.isWrapCollectionsInElement() ) {
309             ElementDescriptor wrappingDescriptor = new ElementDescriptor();
310             wrappingDescriptor.setElementDescriptors( new ElementDescriptor[] { entryDescriptor } );
311             NameMapper nameMapper = configuration.getElementNameMapper();
312             wrappingDescriptor.setLocalName( nameMapper.mapTypeToElementName( propertyName ));
313             result = wrappingDescriptor;
314                         
315         } else {
316             result = entryDescriptor;
317         }
318
319         return result;
320     }
321
322     /**
323      * Creates an <code>ElementDescriptor</code> for a collective type property
324      * @param configuration
325      * @param propertyUpdater, <code>Updater</code> for the property, possibly null
326      * @param propertyExpression
327      * @return
328      */

329     private ElementDescriptor createDescriptorForCollective(
330         IntrospectionConfiguration configuration,
331         Updater propertyUpdater,
332         Expression propertyExpression) {
333             
334         ElementDescriptor result;
335         
336         ElementDescriptor loopDescriptor = new ElementDescriptor();
337         loopDescriptor.setContextExpression(
338             new IteratorExpression( propertyExpression )
339         );
340         loopDescriptor.setPropertyName(getPropertyName());
341         loopDescriptor.setPropertyType(getPropertyType());
342         loopDescriptor.setHollow(true);
343         // set the property updater (if it exists)
344
// may be overridden later by the adder
345
loopDescriptor.setUpdater(propertyUpdater);
346         
347         if ( configuration.isWrapCollectionsInElement() ) {
348             // create wrapping desctiptor
349
ElementDescriptor wrappingDescriptor = new ElementDescriptor();
350             wrappingDescriptor.setElementDescriptors( new ElementDescriptor[] { loopDescriptor } );
351             wrappingDescriptor.setLocalName(
352                 configuration.getElementNameMapper().mapTypeToElementName( propertyName ));
353             result = wrappingDescriptor;
354         
355         } else {
356             // unwrapped Descriptor
357
result = loopDescriptor;
358         }
359         return result;
360     }
361
362     /**
363      * Creates a NodeDescriptor for a primitive type node
364      * @param configuration
365      * @param name
366      * @param log
367      * @param propertyExpression
368      * @param propertyUpdater
369      * @return
370      */

371     private NodeDescriptor createDescriptorForPrimitive(
372         IntrospectionConfiguration configuration,
373         Expression propertyExpression,
374         Updater propertyUpdater) {
375         Log log = configuration.getIntrospectionLog();
376         NodeDescriptor descriptor;
377         if (log.isTraceEnabled()) {
378             log.trace( "Primitive type: " + getPropertyName());
379         }
380         SimpleTypeMapper.Binding binding
381             = configuration.getSimpleTypeMapper().bind(
382                                                         propertyName,
383                                                         propertyType,
384                                                         configuration);
385         if ( SimpleTypeMapper.Binding.ATTRIBUTE.equals( binding )) {
386             if (log.isTraceEnabled()) {
387                 log.trace( "Adding property as attribute: " + getPropertyName() );
388             }
389             descriptor = new AttributeDescriptor();
390         } else {
391             if (log.isTraceEnabled()) {
392                 log.trace( "Adding property as element: " + getPropertyName() );
393             }
394             descriptor = new ElementDescriptor();
395         }
396         descriptor.setTextExpression( propertyExpression );
397         if ( propertyUpdater != null ) {
398             descriptor.setUpdater( propertyUpdater );
399         }
400         configureDescriptor(descriptor, configuration);
401         return descriptor;
402     }
403 }
404
Popular Tags