View Javadoc

1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16  
17  package org.apache.commons.betwixt;
18  
19  import java.util.Collection;
20  import java.util.Enumeration;
21  import java.util.Iterator;
22  import java.util.Map;
23  
24  import org.apache.commons.betwixt.strategy.ClassNormalizer;
25  import org.apache.commons.betwixt.strategy.DefaultNameMapper;
26  import org.apache.commons.betwixt.strategy.DefaultPluralStemmer;
27  import org.apache.commons.betwixt.strategy.MappingDerivationStrategy;
28  import org.apache.commons.betwixt.strategy.NameMapper;
29  import org.apache.commons.betwixt.strategy.NamespacePrefixMapper;
30  import org.apache.commons.betwixt.strategy.PluralStemmer;
31  import org.apache.commons.betwixt.strategy.PropertySuppressionStrategy;
32  import org.apache.commons.betwixt.strategy.SimpleTypeMapper;
33  import org.apache.commons.betwixt.strategy.StandardSimpleTypeMapper;
34  import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /***
39   * <p>Stores introspection phase binding configuration.</p>
40   * <p>
41   * There are two phase in Betwixt's processing. 
42   * The first phase is the introspection of the bean. 
43   * Strutural configuration settings effect this phase. 
44   * The second phase comes when Betwixt dynamically uses reflection 
45   * to execute the mapping. 
46   * This object stores configuration settings pertaining to the first phase.
47   * </p>
48   * <p>
49   * These common settings have been collected into one class so that they can  
50   * be more easily shared not only between the objects that execute the introspection
51   * but also (by a user) between different <code>XMLIntrospector</code>s.
52   * </p>
53   * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
54   * @version $Revision: 190515 $
55   */
56  public class IntrospectionConfiguration {
57  
58      /*** should attributes or elements be used for primitive types */
59      private boolean attributesForPrimitives = false;
60      
61      /*** should we wrap collections in an extra element? */
62      private boolean wrapCollectionsInElement = true;
63  
64      /*** Should the existing bean info search path for java.reflect.Introspector be used? */
65      private boolean useBeanInfoSearchPath = false;
66  
67      // pluggable strategies        
68      /*** The strategy used to detect matching singular and plural properties */
69      private PluralStemmer pluralStemmer;
70      
71      /*** The strategy used to convert bean type names into element names */
72      private NameMapper elementNameMapper;
73  
74      /*** Strategy normalizes the Class of the Object before introspection */
75      private ClassNormalizer classNormalizer = new ClassNormalizer(); 
76      
77      /*** Log for introspection messages */
78      private Log introspectionLog = LogFactory.getLog(XMLIntrospector.class);
79  
80      /***
81       * The strategy used to convert bean type names into attribute names
82       * It will default to the normal nameMapper.
83       */
84      private NameMapper attributeNameMapper;
85  
86      /*** Prefix naming strategy */
87      private NamespacePrefixMapper prefixMapper = new NamespacePrefixMapper();
88      /*** Mapping strategy for simple types */
89      private SimpleTypeMapper simpleTypeMapper = new StandardSimpleTypeMapper();
90      /*** Binding strategy for Java type */
91      private TypeBindingStrategy typeBindingStrategy = TypeBindingStrategy.DEFAULT;
92      
93      
94      /*** 
95       * Strategy used to determine whether the bind or introspection time type is to be used to  
96       * determine the mapping.
97       */
98      	private MappingDerivationStrategy mappingDerivationStrategy = MappingDerivationStrategy.DEFAULT;
99      
100     	/***
101     	 * Strategy used to determine which properties should be ignored
102     	 */
103     	private PropertySuppressionStrategy propertySuppressionStrategy = PropertySuppressionStrategy.DEFAULT;
104     	
105     /***
106       * Gets the <code>ClassNormalizer</code> strategy.
107       * This is used to determine the Class to be introspected
108       * (the normalized Class). 
109       *
110       * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected
111       * for a given Object.
112       */
113     public ClassNormalizer getClassNormalizer() {
114         return classNormalizer;
115     }
116     
117     /***
118       * Sets the <code>ClassNormalizer</code> strategy.
119       * This is used to determine the Class to be introspected
120       * (the normalized Class). 
121       *
122       * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine 
123       * the Class to be introspected for a given Object.
124       */    
125     public void setClassNormalizer(ClassNormalizer classNormalizer) {
126         this.classNormalizer = classNormalizer;
127     }
128 
129     /*** 
130       * Should attributes (or elements) be used for primitive types.
131       * @return true if primitive types will be mapped to attributes in the introspection
132       */
133     public boolean isAttributesForPrimitives() {
134         return attributesForPrimitives;
135     }
136 
137     /*** 
138       * Set whether attributes (or elements) should be used for primitive types. 
139       * @param attributesForPrimitives pass trus to map primitives to attributes,
140       *        pass false to map primitives to elements
141       */
142     public void setAttributesForPrimitives(boolean attributesForPrimitives) {
143         this.attributesForPrimitives = attributesForPrimitives;
144     }
145     
146     /***
147      * Should collections be wrapped in an extra element?
148      * 
149      * @return whether we should we wrap collections in an extra element? 
150      */
151     public boolean isWrapCollectionsInElement() {
152         return wrapCollectionsInElement;
153     }
154 
155     /*** 
156      * Sets whether we should we wrap collections in an extra element.
157      *
158      * @param wrapCollectionsInElement pass true if collections should be wrapped in a
159      *        parent element
160      */
161     public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) {
162         this.wrapCollectionsInElement = wrapCollectionsInElement;
163     }    
164 
165     /*** 
166      * Get singular and plural matching strategy.
167      *
168      * @return the strategy used to detect matching singular and plural properties 
169      */
170     public PluralStemmer getPluralStemmer() {
171         if ( pluralStemmer == null ) {
172             pluralStemmer = createPluralStemmer();
173         }
174         return pluralStemmer;
175     }
176     
177     /*** 
178      * Sets the strategy used to detect matching singular and plural properties 
179      *
180      * @param pluralStemmer the PluralStemmer used to match singular and plural
181      */
182     public void setPluralStemmer(PluralStemmer pluralStemmer) {
183         this.pluralStemmer = pluralStemmer;
184     }
185     
186     /***
187      * Gets the name mapping strategy used to convert bean names into elements.
188      *
189      * @return the strategy used to convert bean type names into element 
190      * names. If no element mapper is currently defined then a default one is created.
191      */
192     public NameMapper getElementNameMapper() {
193         if ( elementNameMapper == null ) {
194             elementNameMapper = createNameMapper();
195          }
196         return elementNameMapper;
197     }
198      
199     /***
200      * Sets the strategy used to convert bean type names into element names
201      * @param nameMapper the NameMapper to use for the conversion
202      */
203     public void setElementNameMapper(NameMapper nameMapper) {
204         this.elementNameMapper = nameMapper;
205     }
206     
207     /***
208      * Gets the name mapping strategy used to convert bean names into attributes.
209      *
210      * @return the strategy used to convert bean type names into attribute
211      * names. If no attributeNamemapper is known, it will default to the ElementNameMapper
212      */
213     public NameMapper getAttributeNameMapper() {
214         if (attributeNameMapper == null) {
215             attributeNameMapper = createNameMapper();
216         }
217         return attributeNameMapper;
218      }
219 
220 
221     /***
222      * Sets the strategy used to convert bean type names into attribute names
223      * @param nameMapper the NameMapper to use for the convertion
224      */
225     public void setAttributeNameMapper(NameMapper nameMapper) {
226         this.attributeNameMapper = nameMapper;
227     }
228     
229     /***
230      * <p>Should the original <code>java.reflect.Introspector</code> bean info search path be used?</p>
231      * <p>
232      * Default is false.
233      * </p>
234      * 
235      * @return boolean if the beanInfoSearchPath should be used.
236      */
237     public boolean useBeanInfoSearchPath() {
238         return useBeanInfoSearchPath;
239     }
240 
241     /***
242      * Specifies if you want to use the beanInfoSearchPath 
243      * @see java.beans.Introspector for more details
244      * @param useBeanInfoSearchPath 
245      */
246     public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
247         this.useBeanInfoSearchPath = useBeanInfoSearchPath;
248     }
249     
250     /*** 
251      * A Factory method to lazily create a new strategy 
252      * to detect matching singular and plural properties.
253      *
254      * @return new defualt PluralStemmer implementation
255      */
256     protected PluralStemmer createPluralStemmer() {
257         return new DefaultPluralStemmer();
258     }
259     
260     /*** 
261      * A Factory method to lazily create a strategy 
262      * used to convert bean type names into element names.
263      *
264      * @return new default NameMapper implementation
265      */
266     protected NameMapper createNameMapper() {
267         return new DefaultNameMapper();
268     }
269     
270     /***
271      * Gets the common Log used for introspection.
272      * It is more convenient to use a single Log
273      * that can be easily configured.
274      * @return Log, not null
275      */
276     public Log getIntrospectionLog() {
277         return introspectionLog;
278     }
279 
280     /***
281      * Sets the common Log used by introspection.
282      * It is more convenient to use a single Log
283      * that can be easily configured.
284      * @param log Log, not null
285      */
286     public void setIntrospectionLog(Log log) {
287         introspectionLog = log;
288     }
289 
290     
291     /***
292      * Gets the <code>NamespacePrefixMapper</code> used to convert namespace URIs 
293      * into prefixes.
294      * @return NamespacePrefixMapper, not null
295      */
296     public NamespacePrefixMapper getPrefixMapper() {
297         return prefixMapper;
298     }
299 
300     /***
301      * Sets the <code>NamespacePrefixMapper</code> used to convert namespave URIs
302      * into prefixes.
303      * @param mapper NamespacePrefixMapper, not null
304      */
305     public void setPrefixMapper(NamespacePrefixMapper mapper) {
306         prefixMapper = mapper;
307     }
308     
309     
310     /***
311      * Gets the simple type binding strategy.
312      * @return SimpleTypeMapper, not null
313      */
314     public SimpleTypeMapper getSimpleTypeMapper() {
315         return simpleTypeMapper;
316     }
317 
318     /***
319      * Sets the simple type binding strategy.
320      * @param mapper SimpleTypeMapper, not null
321      */
322     public void setSimpleTypeMapper(SimpleTypeMapper mapper) {
323         simpleTypeMapper = mapper;
324     }
325 
326     /***
327      * Gets the <code>TypeBindingStrategy</code> to be used
328      * to determine the binding for Java types.
329      * @return the <code>TypeBindingStrategy</code> to be used, 
330      * not null
331      */
332     public TypeBindingStrategy getTypeBindingStrategy() {
333         return typeBindingStrategy;
334     }
335     
336     /***
337      * Sets the <code>TypeBindingStrategy</code> to be used
338      * to determine the binding for Java types.
339      * @param typeBindingStrategy the <code>TypeBindingStrategy</code> to be used,
340      * not null
341      */
342     public void setTypeBindingStrategy(TypeBindingStrategy typeBindingStrategy) {
343         this.typeBindingStrategy = typeBindingStrategy;
344     }
345     
346     
347     /***
348      * Gets the <code>MappingDerivationStrategy</code>
349      * used to determine whether the bind or introspection time
350      * type should determine the mapping.
351      * @since 0.7
352      * @return <code>MappingDerivationStrategy</code>, not null
353      */
354     public MappingDerivationStrategy getMappingDerivationStrategy() {
355         return mappingDerivationStrategy;
356     }
357     /***
358      * Sets the <code>MappingDerivationStrategy</code>
359      * used to determine whether the bind or introspection time
360      * type should determine the mapping.
361      * @since 0.7
362      * @param mappingDerivationStrategy <code>MappingDerivationStrategy</code>, not null
363      */
364     public void setMappingDerivationStrategy(
365             MappingDerivationStrategy mappingDerivationStrategy) {
366         this.mappingDerivationStrategy = mappingDerivationStrategy;
367     }
368 
369     /***
370      * Gets the strategy which determines the properties to be ignored.
371      * @since 0.7
372      * @return the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
373      */
374     public PropertySuppressionStrategy getPropertySuppressionStrategy() {
375         return propertySuppressionStrategy;
376     }
377     
378     /***
379      * Sets the strategy which determines the properties to be ignored.
380      * @since 0.7
381      * @param propertySuppressionStrategy the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
382      */
383     public void setPropertySuppressionStrategy(
384             PropertySuppressionStrategy propertySuppressionStrategy) {
385         this.propertySuppressionStrategy = propertySuppressionStrategy;
386     }
387     
388     /*** 
389      * Is this a loop type class?
390      * @since 0.7
391      * @param type is this <code>Class</code> a loop type?
392      * @return true if the type is a loop type, or if type is null 
393      */
394     public boolean isLoopType(Class type) {
395         // consider: should this be factored into a pluggable strategy?
396         // check for NPEs
397         if (type == null) {
398             return false;
399         }
400         return type.isArray() 
401             || Map.class.isAssignableFrom( type ) 
402             || Collection.class.isAssignableFrom( type ) 
403             || Enumeration.class.isAssignableFrom( type ) 
404             || Iterator.class.isAssignableFrom( type )
405             || Map.Entry.class.isAssignableFrom( type ) ;
406     }
407 }