View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  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  package org.apache.commons.betwixt;
19  
20  import org.apache.commons.betwixt.strategy.AttributeSuppressionStrategy;
21  import org.apache.commons.betwixt.strategy.ClassNormalizer;
22  import org.apache.commons.betwixt.strategy.CollectiveTypeStrategy;
23  import org.apache.commons.betwixt.strategy.DefaultNameMapper;
24  import org.apache.commons.betwixt.strategy.DefaultPluralStemmer;
25  import org.apache.commons.betwixt.strategy.ElementSuppressionStrategy;
26  import org.apache.commons.betwixt.strategy.MappingDerivationStrategy;
27  import org.apache.commons.betwixt.strategy.NameMapper;
28  import org.apache.commons.betwixt.strategy.NamespacePrefixMapper;
29  import org.apache.commons.betwixt.strategy.PluralStemmer;
30  import org.apache.commons.betwixt.strategy.PropertySuppressionStrategy;
31  import org.apache.commons.betwixt.strategy.SimpleTypeMapper;
32  import org.apache.commons.betwixt.strategy.StandardSimpleTypeMapper;
33  import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  /**
38   * <p>Stores introspection phase binding configuration.</p>
39   * <p>
40   * There are two phase in Betwixt's processing. 
41   * The first phase is the introspection of the bean. 
42   * Strutural configuration settings effect this phase. 
43   * The second phase comes when Betwixt dynamically uses reflection 
44   * to execute the mapping. 
45   * This object stores configuration settings pertaining to the first phase.
46   * </p>
47   * <p>
48   * These common settings have been collected into one class so that they can  
49   * be more easily shared not only between the objects that execute the introspection
50   * but also (by a user) between different <code>XMLIntrospector</code>s.
51   * </p>
52   * @author <a href='http://commons.apache.org/'>Apache Commons Team</a>
53   * @version $Revision: 561314 $
54   */
55  public class IntrospectionConfiguration {
56  
57      /** should attributes or elements be used for primitive types */
58      private boolean attributesForPrimitives = false;
59      
60      /** should we wrap collections in an extra element? */
61      private boolean wrapCollectionsInElement = true;
62  
63      /** Should the existing bean info search path for java.reflect.Introspector be used? */
64      private boolean useBeanInfoSearchPath = false;
65      
66      /** Should existing BeanInfo classes be used at all for java.reflect.Introspector */
67      private boolean ignoreAllBeanInfo = false;
68  
69      // pluggable strategies        
70      /** The strategy used to detect matching singular and plural properties */
71      private PluralStemmer pluralStemmer;
72      
73      /** The strategy used to convert bean type names into element names */
74      private NameMapper elementNameMapper;
75  
76      /** Strategy normalizes the Class of the Object before introspection */
77      private ClassNormalizer classNormalizer = new ClassNormalizer(); 
78      
79      /** Log for introspection messages */
80      private Log introspectionLog = LogFactory.getLog(XMLIntrospector.class);
81  
82      /**
83       * The strategy used to convert bean type names into attribute names
84       * It will default to the normal nameMapper.
85       */
86      private NameMapper attributeNameMapper;
87  
88      /** Prefix naming strategy */
89      private NamespacePrefixMapper prefixMapper = new NamespacePrefixMapper();
90      /** Mapping strategy for simple types */
91      private SimpleTypeMapper simpleTypeMapper = new StandardSimpleTypeMapper();
92      /** Binding strategy for Java type */
93      private TypeBindingStrategy typeBindingStrategy = TypeBindingStrategy.DEFAULT;
94      /** Strategy used for determining which types are collective */
95      private CollectiveTypeStrategy collectiveTypeStrategy = CollectiveTypeStrategy.DEFAULT;
96  
97      /** Strategy for suppressing attributes */
98      private AttributeSuppressionStrategy attributeSuppressionStrategy = AttributeSuppressionStrategy.DEFAULT;   
99      /** Strategy for suppressing elements */
100     private ElementSuppressionStrategy elementSuppressionStrategy = ElementSuppressionStrategy.DEFAULT;
101 
102     
103     /** 
104      * Strategy used to determine whether the bind or introspection time type is to be used to  
105      * determine the mapping.
106      */
107     	private MappingDerivationStrategy mappingDerivationStrategy = MappingDerivationStrategy.DEFAULT;
108     
109     	/**
110     	 * Strategy used to determine which properties should be ignored
111     	 */
112     	private PropertySuppressionStrategy propertySuppressionStrategy = PropertySuppressionStrategy.DEFAULT;
113     	
114         /**
115          * Should the introspector use the context classloader. Defaults to true.
116          */
117         private boolean useContextClassLoader = true;
118         
119     /**
120       * Gets the <code>ClassNormalizer</code> strategy.
121       * This is used to determine the Class to be introspected
122       * (the normalized Class). 
123       *
124       * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected
125       * for a given Object.
126       */
127     public ClassNormalizer getClassNormalizer() {
128         return classNormalizer;
129     }
130     
131     /**
132       * Sets the <code>ClassNormalizer</code> strategy.
133       * This is used to determine the Class to be introspected
134       * (the normalized Class). 
135       *
136       * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine 
137       * the Class to be introspected for a given Object.
138       */    
139     public void setClassNormalizer(ClassNormalizer classNormalizer) {
140         this.classNormalizer = classNormalizer;
141     }
142 
143     /** 
144       * Should attributes (or elements) be used for primitive types.
145       * @return true if primitive types will be mapped to attributes in the introspection
146       */
147     public boolean isAttributesForPrimitives() {
148         return attributesForPrimitives;
149     }
150 
151     /** 
152       * Set whether attributes (or elements) should be used for primitive types. 
153       * @param attributesForPrimitives pass trus to map primitives to attributes,
154       *        pass false to map primitives to elements
155       */
156     public void setAttributesForPrimitives(boolean attributesForPrimitives) {
157         this.attributesForPrimitives = attributesForPrimitives;
158     }
159     
160     /**
161      * Should collections be wrapped in an extra element?
162      * 
163      * @return whether we should we wrap collections in an extra element? 
164      */
165     public boolean isWrapCollectionsInElement() {
166         return wrapCollectionsInElement;
167     }
168 
169     /** 
170      * Sets whether we should we wrap collections in an extra element.
171      *
172      * @param wrapCollectionsInElement pass true if collections should be wrapped in a
173      *        parent element
174      */
175     public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) {
176         this.wrapCollectionsInElement = wrapCollectionsInElement;
177     }    
178 
179     /** 
180      * Get singular and plural matching strategy.
181      *
182      * @return the strategy used to detect matching singular and plural properties 
183      */
184     public PluralStemmer getPluralStemmer() {
185         if ( pluralStemmer == null ) {
186             pluralStemmer = createPluralStemmer();
187         }
188         return pluralStemmer;
189     }
190     
191     /** 
192      * Sets the strategy used to detect matching singular and plural properties 
193      *
194      * @param pluralStemmer the PluralStemmer used to match singular and plural
195      */
196     public void setPluralStemmer(PluralStemmer pluralStemmer) {
197         this.pluralStemmer = pluralStemmer;
198     }
199     
200     /**
201      * Gets the name mapping strategy used to convert bean names into elements.
202      *
203      * @return the strategy used to convert bean type names into element 
204      * names. If no element mapper is currently defined then a default one is created.
205      */
206     public NameMapper getElementNameMapper() {
207         if ( elementNameMapper == null ) {
208             elementNameMapper = createNameMapper();
209          }
210         return elementNameMapper;
211     }
212      
213     /**
214      * Sets the strategy used to convert bean type names into element names
215      * @param nameMapper the NameMapper to use for the conversion
216      */
217     public void setElementNameMapper(NameMapper nameMapper) {
218         this.elementNameMapper = nameMapper;
219     }
220     
221     /**
222      * Gets the name mapping strategy used to convert bean names into attributes.
223      *
224      * @return the strategy used to convert bean type names into attribute
225      * names. If no attributeNamemapper is known, it will default to the ElementNameMapper
226      */
227     public NameMapper getAttributeNameMapper() {
228         if (attributeNameMapper == null) {
229             attributeNameMapper = createNameMapper();
230         }
231         return attributeNameMapper;
232      }
233 
234 
235     /**
236      * Sets the strategy used to convert bean type names into attribute names
237      * @param nameMapper the NameMapper to use for the convertion
238      */
239     public void setAttributeNameMapper(NameMapper nameMapper) {
240         this.attributeNameMapper = nameMapper;
241     }
242     
243     /**
244      * <p>Should the original <code>java.reflect.Introspector</code> bean info search path be used?</p>
245      * <p>
246      * Default is false.
247      * </p>
248      * 
249      * @return boolean if the beanInfoSearchPath should be used.
250      */
251     public boolean useBeanInfoSearchPath() {
252         return useBeanInfoSearchPath;
253     }
254 
255     /**
256      * Specifies if you want to use the beanInfoSearchPath 
257      * @see java.beans.Introspector for more details
258      * @param useBeanInfoSearchPath 
259      */
260     public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
261         this.useBeanInfoSearchPath = useBeanInfoSearchPath;
262     }
263     
264     /**
265      * <p>Should existing BeanInfo classes be ignored by <code>java.reflect.Introspector</code>.</p>
266      * <p>
267      * Default is false.
268      * </p>
269      * 
270      * @return boolean if the BeanInfo classes should be used.
271      */
272     public boolean ignoreAllBeanInfo() {
273         return ignoreAllBeanInfo;
274     }
275     
276     /**
277      * Specifies if you want to ignore existing BeanInfo classes at all for introspection
278      * @see java.beans.Introspector for more details
279      * @param ignoreAllBeanInfo set to true to ignore all BeanInfo classes
280      * @since 0.8
281      */
282     public void setIgnoreAllBeanInfo(boolean ignoreAllBeanInfo) {
283         this.ignoreAllBeanInfo = ignoreAllBeanInfo;
284     }
285     
286     
287     /** 
288      * A Factory method to lazily create a new strategy 
289      * to detect matching singular and plural properties.
290      *
291      * @return new defualt PluralStemmer implementation
292      */
293     protected PluralStemmer createPluralStemmer() {
294         return new DefaultPluralStemmer();
295     }
296     
297     /** 
298      * A Factory method to lazily create a strategy 
299      * used to convert bean type names into element names.
300      *
301      * @return new default NameMapper implementation
302      */
303     protected NameMapper createNameMapper() {
304         return new DefaultNameMapper();
305     }
306     
307     /**
308      * Gets the common Log used for introspection.
309      * It is more convenient to use a single Log
310      * that can be easily configured.
311      * @return Log, not null
312      */
313     public Log getIntrospectionLog() {
314         return introspectionLog;
315     }
316 
317     /**
318      * Sets the common Log used by introspection.
319      * It is more convenient to use a single Log
320      * that can be easily configured.
321      * @param log Log, not null
322      */
323     public void setIntrospectionLog(Log log) {
324         introspectionLog = log;
325     }
326 
327     
328     /**
329      * Gets the <code>NamespacePrefixMapper</code> used to convert namespace URIs 
330      * into prefixes.
331      * @return NamespacePrefixMapper, not null
332      */
333     public NamespacePrefixMapper getPrefixMapper() {
334         return prefixMapper;
335     }
336 
337     /**
338      * Sets the <code>NamespacePrefixMapper</code> used to convert namespave URIs
339      * into prefixes.
340      * @param mapper NamespacePrefixMapper, not null
341      */
342     public void setPrefixMapper(NamespacePrefixMapper mapper) {
343         prefixMapper = mapper;
344     }
345     
346     
347     /**
348      * Gets the simple type binding strategy.
349      * @return SimpleTypeMapper, not null
350      */
351     public SimpleTypeMapper getSimpleTypeMapper() {
352         return simpleTypeMapper;
353     }
354 
355     /**
356      * Sets the simple type binding strategy.
357      * @param mapper SimpleTypeMapper, not null
358      */
359     public void setSimpleTypeMapper(SimpleTypeMapper mapper) {
360         simpleTypeMapper = mapper;
361     }
362 
363     /**
364      * Gets the <code>TypeBindingStrategy</code> to be used
365      * to determine the binding for Java types.
366      * @return the <code>TypeBindingStrategy</code> to be used, 
367      * not null
368      */
369     public TypeBindingStrategy getTypeBindingStrategy() {
370         return typeBindingStrategy;
371     }
372     
373     /**
374      * Sets the <code>TypeBindingStrategy</code> to be used
375      * to determine the binding for Java types.
376      * @param typeBindingStrategy the <code>TypeBindingStrategy</code> to be used,
377      * not null
378      */
379     public void setTypeBindingStrategy(TypeBindingStrategy typeBindingStrategy) {
380         this.typeBindingStrategy = typeBindingStrategy;
381     }
382     
383     
384     /**
385      * Gets the <code>MappingDerivationStrategy</code>
386      * used to determine whether the bind or introspection time
387      * type should determine the mapping.
388      * @since 0.7
389      * @return <code>MappingDerivationStrategy</code>, not null
390      */
391     public MappingDerivationStrategy getMappingDerivationStrategy() {
392         return mappingDerivationStrategy;
393     }
394     /**
395      * Sets the <code>MappingDerivationStrategy</code>
396      * used to determine whether the bind or introspection time
397      * type should determine the mapping.
398      * @since 0.7
399      * @param mappingDerivationStrategy <code>MappingDerivationStrategy</code>, not null
400      */
401     public void setMappingDerivationStrategy(
402             MappingDerivationStrategy mappingDerivationStrategy) {
403         this.mappingDerivationStrategy = mappingDerivationStrategy;
404     }
405 
406     /**
407      * Gets the strategy which determines the properties to be ignored.
408      * @since 0.7
409      * @return the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
410      */
411     public PropertySuppressionStrategy getPropertySuppressionStrategy() {
412         return propertySuppressionStrategy;
413     }
414     
415     /**
416      * Sets the strategy which determines the properties to be ignored.
417      * @since 0.7
418      * @param propertySuppressionStrategy the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
419      */
420     public void setPropertySuppressionStrategy(
421             PropertySuppressionStrategy propertySuppressionStrategy) {
422         this.propertySuppressionStrategy = propertySuppressionStrategy;
423     }
424     
425     /**
426      * Gets the strategy used to determine which types are collective.
427      * @return <code>CollectiveTypeStrategy</code>, not null
428      * @since 0.8
429      */
430     public CollectiveTypeStrategy getCollectiveTypeStrategy() {
431         return collectiveTypeStrategy;
432     }
433 
434     /**
435      * Sets the strategy used to determine which types are collective.
436      * @param collectiveTypeStrategy <code>CollectiveTypeStrategy</code>, not null
437      * @since 0.8
438      */
439     public void setCollectiveTypeStrategy(
440             CollectiveTypeStrategy collectiveTypeStrategy) {
441         this.collectiveTypeStrategy = collectiveTypeStrategy;
442     }
443 
444     /** 
445      * Is this a loop type class?
446      * @since 0.7
447      * @param type is this <code>Class</code> a loop type?
448      * @return true if the type is a loop type, or if type is null 
449      */
450     public boolean isLoopType(Class type) {
451         return getCollectiveTypeStrategy().isCollective(type);
452     }
453 
454 
455     /**
456      * Returns the <code>AttributeSuppressionStrategy</code>. 
457      * This is used to suppress attributes, e.g. for versioning.
458      * 
459      * @since 0.8
460      * @return the strategy
461      */
462     public AttributeSuppressionStrategy getAttributeSuppressionStrategy() {
463         return attributeSuppressionStrategy;
464     }
465 
466     /**
467      * Sets the <code>AttributeSuppressionStrategy</code>. 
468      * This is used to suppress attributes, e.g. for versioning.
469      * 
470      * @since 0.8
471      * @param attributeSuppressionStrategy the strategy 
472      */
473     public void setAttributeSuppressionStrategy(
474             AttributeSuppressionStrategy attributeSuppressionStrategy) {
475         this.attributeSuppressionStrategy = attributeSuppressionStrategy;
476     }
477 
478     /**
479      * Returns the <code>ElementSuppressionStrategy</code>. 
480      * This is used to suppress elements, e.g. for versioning.
481      * 
482      * @since 0.8
483      * @return the strategy
484      */
485     public ElementSuppressionStrategy getElementSuppressionStrategy() {
486         return elementSuppressionStrategy;
487     }
488 
489     /**
490      * Sets the <code>ElementSuppressionStrategy</code>. 
491      * This is used to suppress elements, e.g. for versioning.
492      * 
493      * @since 0.8
494      * @param elementSuppressionStrategy the strategy 
495      */
496     public void setElementSuppressionStrategy(
497             ElementSuppressionStrategy elementSuppressionStrategy) {
498         this.elementSuppressionStrategy = elementSuppressionStrategy;
499     }
500 
501     /**
502      * Should be context classloader be used when loading classes?
503      * @return <code>true</code> if the context classloader is to be used during introspection, 
504      * <code>false</code> otherwise.
505      */
506     public boolean isUseContextClassLoader() {
507         return useContextClassLoader;
508     }
509 
510     /**
511      * <p>Specify whether the context classloader should be used to load classes during introspection;
512      * the default value is true.</p>
513      * <p>
514      * When running code that is not in a container (ie where the context classloader is the same
515      * as the system classloader), this setting has no effect. When running code in containers that
516      * do define a context classloader for loaded "components" (eg webapps), a true value will allow
517      * classes in the loaded "component" to be accessable even when Betwixt is deployed via a
518      * "higher level" classloader.
519      * </p>
520      * <p>
521      * If code is running in a container that uses a context classloader in unusual ways then it
522      * may be necessary to set this value to false. In this case, classes are always loaded using the
523      * same classloader that loaded the betwixt library.
524      * </p>
525      */
526     public void setUseContextClassLoader(boolean useContextClassLoader) {
527         this.useContextClassLoader = useContextClassLoader;
528     }
529 }