001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.betwixt;
019:
020: import org.apache.commons.betwixt.strategy.AttributeSuppressionStrategy;
021: import org.apache.commons.betwixt.strategy.ClassNormalizer;
022: import org.apache.commons.betwixt.strategy.CollectiveTypeStrategy;
023: import org.apache.commons.betwixt.strategy.DefaultNameMapper;
024: import org.apache.commons.betwixt.strategy.DefaultPluralStemmer;
025: import org.apache.commons.betwixt.strategy.ElementSuppressionStrategy;
026: import org.apache.commons.betwixt.strategy.MappingDerivationStrategy;
027: import org.apache.commons.betwixt.strategy.NameMapper;
028: import org.apache.commons.betwixt.strategy.NamespacePrefixMapper;
029: import org.apache.commons.betwixt.strategy.PluralStemmer;
030: import org.apache.commons.betwixt.strategy.PropertySuppressionStrategy;
031: import org.apache.commons.betwixt.strategy.SimpleTypeMapper;
032: import org.apache.commons.betwixt.strategy.StandardSimpleTypeMapper;
033: import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036:
037: /**
038: * <p>Stores introspection phase binding configuration.</p>
039: * <p>
040: * There are two phase in Betwixt's processing.
041: * The first phase is the introspection of the bean.
042: * Strutural configuration settings effect this phase.
043: * The second phase comes when Betwixt dynamically uses reflection
044: * to execute the mapping.
045: * This object stores configuration settings pertaining to the first phase.
046: * </p>
047: * <p>
048: * These common settings have been collected into one class so that they can
049: * be more easily shared not only between the objects that execute the introspection
050: * but also (by a user) between different <code>XMLIntrospector</code>s.
051: * </p>
052: * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
053: * @version $Revision: 471234 $
054: */
055: public class IntrospectionConfiguration {
056:
057: /** should attributes or elements be used for primitive types */
058: private boolean attributesForPrimitives = false;
059:
060: /** should we wrap collections in an extra element? */
061: private boolean wrapCollectionsInElement = true;
062:
063: /** Should the existing bean info search path for java.reflect.Introspector be used? */
064: private boolean useBeanInfoSearchPath = false;
065:
066: /** Should existing BeanInfo classes be used at all for java.reflect.Introspector */
067: private boolean ignoreAllBeanInfo = false;
068:
069: // pluggable strategies
070: /** The strategy used to detect matching singular and plural properties */
071: private PluralStemmer pluralStemmer;
072:
073: /** The strategy used to convert bean type names into element names */
074: private NameMapper elementNameMapper;
075:
076: /** Strategy normalizes the Class of the Object before introspection */
077: private ClassNormalizer classNormalizer = new ClassNormalizer();
078:
079: /** Log for introspection messages */
080: private Log introspectionLog = LogFactory
081: .getLog(XMLIntrospector.class);
082:
083: /**
084: * The strategy used to convert bean type names into attribute names
085: * It will default to the normal nameMapper.
086: */
087: private NameMapper attributeNameMapper;
088:
089: /** Prefix naming strategy */
090: private NamespacePrefixMapper prefixMapper = new NamespacePrefixMapper();
091: /** Mapping strategy for simple types */
092: private SimpleTypeMapper simpleTypeMapper = new StandardSimpleTypeMapper();
093: /** Binding strategy for Java type */
094: private TypeBindingStrategy typeBindingStrategy = TypeBindingStrategy.DEFAULT;
095: /** Strategy used for determining which types are collective */
096: private CollectiveTypeStrategy collectiveTypeStrategy = CollectiveTypeStrategy.DEFAULT;
097:
098: /** Strategy for suppressing attributes */
099: private AttributeSuppressionStrategy attributeSuppressionStrategy = AttributeSuppressionStrategy.DEFAULT;
100: /** Strategy for suppressing elements */
101: private ElementSuppressionStrategy elementSuppressionStrategy = ElementSuppressionStrategy.DEFAULT;
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: * Gets the <code>ClassNormalizer</code> strategy.
116: * This is used to determine the Class to be introspected
117: * (the normalized Class).
118: *
119: * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected
120: * for a given Object.
121: */
122: public ClassNormalizer getClassNormalizer() {
123: return classNormalizer;
124: }
125:
126: /**
127: * Sets the <code>ClassNormalizer</code> strategy.
128: * This is used to determine the Class to be introspected
129: * (the normalized Class).
130: *
131: * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine
132: * the Class to be introspected for a given Object.
133: */
134: public void setClassNormalizer(ClassNormalizer classNormalizer) {
135: this .classNormalizer = classNormalizer;
136: }
137:
138: /**
139: * Should attributes (or elements) be used for primitive types.
140: * @return true if primitive types will be mapped to attributes in the introspection
141: */
142: public boolean isAttributesForPrimitives() {
143: return attributesForPrimitives;
144: }
145:
146: /**
147: * Set whether attributes (or elements) should be used for primitive types.
148: * @param attributesForPrimitives pass trus to map primitives to attributes,
149: * pass false to map primitives to elements
150: */
151: public void setAttributesForPrimitives(
152: boolean attributesForPrimitives) {
153: this .attributesForPrimitives = attributesForPrimitives;
154: }
155:
156: /**
157: * Should collections be wrapped in an extra element?
158: *
159: * @return whether we should we wrap collections in an extra element?
160: */
161: public boolean isWrapCollectionsInElement() {
162: return wrapCollectionsInElement;
163: }
164:
165: /**
166: * Sets whether we should we wrap collections in an extra element.
167: *
168: * @param wrapCollectionsInElement pass true if collections should be wrapped in a
169: * parent element
170: */
171: public void setWrapCollectionsInElement(
172: boolean wrapCollectionsInElement) {
173: this .wrapCollectionsInElement = wrapCollectionsInElement;
174: }
175:
176: /**
177: * Get singular and plural matching strategy.
178: *
179: * @return the strategy used to detect matching singular and plural properties
180: */
181: public PluralStemmer getPluralStemmer() {
182: if (pluralStemmer == null) {
183: pluralStemmer = createPluralStemmer();
184: }
185: return pluralStemmer;
186: }
187:
188: /**
189: * Sets the strategy used to detect matching singular and plural properties
190: *
191: * @param pluralStemmer the PluralStemmer used to match singular and plural
192: */
193: public void setPluralStemmer(PluralStemmer pluralStemmer) {
194: this .pluralStemmer = pluralStemmer;
195: }
196:
197: /**
198: * Gets the name mapping strategy used to convert bean names into elements.
199: *
200: * @return the strategy used to convert bean type names into element
201: * names. If no element mapper is currently defined then a default one is created.
202: */
203: public NameMapper getElementNameMapper() {
204: if (elementNameMapper == null) {
205: elementNameMapper = createNameMapper();
206: }
207: return elementNameMapper;
208: }
209:
210: /**
211: * Sets the strategy used to convert bean type names into element names
212: * @param nameMapper the NameMapper to use for the conversion
213: */
214: public void setElementNameMapper(NameMapper nameMapper) {
215: this .elementNameMapper = nameMapper;
216: }
217:
218: /**
219: * Gets the name mapping strategy used to convert bean names into attributes.
220: *
221: * @return the strategy used to convert bean type names into attribute
222: * names. If no attributeNamemapper is known, it will default to the ElementNameMapper
223: */
224: public NameMapper getAttributeNameMapper() {
225: if (attributeNameMapper == null) {
226: attributeNameMapper = createNameMapper();
227: }
228: return attributeNameMapper;
229: }
230:
231: /**
232: * Sets the strategy used to convert bean type names into attribute names
233: * @param nameMapper the NameMapper to use for the convertion
234: */
235: public void setAttributeNameMapper(NameMapper nameMapper) {
236: this .attributeNameMapper = nameMapper;
237: }
238:
239: /**
240: * <p>Should the original <code>java.reflect.Introspector</code> bean info search path be used?</p>
241: * <p>
242: * Default is false.
243: * </p>
244: *
245: * @return boolean if the beanInfoSearchPath should be used.
246: */
247: public boolean useBeanInfoSearchPath() {
248: return useBeanInfoSearchPath;
249: }
250:
251: /**
252: * Specifies if you want to use the beanInfoSearchPath
253: * @see java.beans.Introspector for more details
254: * @param useBeanInfoSearchPath
255: */
256: public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
257: this .useBeanInfoSearchPath = useBeanInfoSearchPath;
258: }
259:
260: /**
261: * <p>Should existing BeanInfo classes be ignored by <code>java.reflect.Introspector</code>.</p>
262: * <p>
263: * Default is false.
264: * </p>
265: *
266: * @return boolean if the BeanInfo classes should be used.
267: */
268: public boolean ignoreAllBeanInfo() {
269: return ignoreAllBeanInfo;
270: }
271:
272: /**
273: * Specifies if you want to ignore existing BeanInfo classes at all for introspection
274: * @see java.beans.Introspector for more details
275: * @param ignoreAllBeanInfo set to true to ignore all BeanInfo classes
276: * @since 0.8
277: */
278: public void setIgnoreAllBeanInfo(boolean ignoreAllBeanInfo) {
279: this .ignoreAllBeanInfo = ignoreAllBeanInfo;
280: }
281:
282: /**
283: * A Factory method to lazily create a new strategy
284: * to detect matching singular and plural properties.
285: *
286: * @return new defualt PluralStemmer implementation
287: */
288: protected PluralStemmer createPluralStemmer() {
289: return new DefaultPluralStemmer();
290: }
291:
292: /**
293: * A Factory method to lazily create a strategy
294: * used to convert bean type names into element names.
295: *
296: * @return new default NameMapper implementation
297: */
298: protected NameMapper createNameMapper() {
299: return new DefaultNameMapper();
300: }
301:
302: /**
303: * Gets the common Log used for introspection.
304: * It is more convenient to use a single Log
305: * that can be easily configured.
306: * @return Log, not null
307: */
308: public Log getIntrospectionLog() {
309: return introspectionLog;
310: }
311:
312: /**
313: * Sets the common Log used by introspection.
314: * It is more convenient to use a single Log
315: * that can be easily configured.
316: * @param log Log, not null
317: */
318: public void setIntrospectionLog(Log log) {
319: introspectionLog = log;
320: }
321:
322: /**
323: * Gets the <code>NamespacePrefixMapper</code> used to convert namespace URIs
324: * into prefixes.
325: * @return NamespacePrefixMapper, not null
326: */
327: public NamespacePrefixMapper getPrefixMapper() {
328: return prefixMapper;
329: }
330:
331: /**
332: * Sets the <code>NamespacePrefixMapper</code> used to convert namespave URIs
333: * into prefixes.
334: * @param mapper NamespacePrefixMapper, not null
335: */
336: public void setPrefixMapper(NamespacePrefixMapper mapper) {
337: prefixMapper = mapper;
338: }
339:
340: /**
341: * Gets the simple type binding strategy.
342: * @return SimpleTypeMapper, not null
343: */
344: public SimpleTypeMapper getSimpleTypeMapper() {
345: return simpleTypeMapper;
346: }
347:
348: /**
349: * Sets the simple type binding strategy.
350: * @param mapper SimpleTypeMapper, not null
351: */
352: public void setSimpleTypeMapper(SimpleTypeMapper mapper) {
353: simpleTypeMapper = mapper;
354: }
355:
356: /**
357: * Gets the <code>TypeBindingStrategy</code> to be used
358: * to determine the binding for Java types.
359: * @return the <code>TypeBindingStrategy</code> to be used,
360: * not null
361: */
362: public TypeBindingStrategy getTypeBindingStrategy() {
363: return typeBindingStrategy;
364: }
365:
366: /**
367: * Sets the <code>TypeBindingStrategy</code> to be used
368: * to determine the binding for Java types.
369: * @param typeBindingStrategy the <code>TypeBindingStrategy</code> to be used,
370: * not null
371: */
372: public void setTypeBindingStrategy(
373: TypeBindingStrategy typeBindingStrategy) {
374: this .typeBindingStrategy = typeBindingStrategy;
375: }
376:
377: /**
378: * Gets the <code>MappingDerivationStrategy</code>
379: * used to determine whether the bind or introspection time
380: * type should determine the mapping.
381: * @since 0.7
382: * @return <code>MappingDerivationStrategy</code>, not null
383: */
384: public MappingDerivationStrategy getMappingDerivationStrategy() {
385: return mappingDerivationStrategy;
386: }
387:
388: /**
389: * Sets the <code>MappingDerivationStrategy</code>
390: * used to determine whether the bind or introspection time
391: * type should determine the mapping.
392: * @since 0.7
393: * @param mappingDerivationStrategy <code>MappingDerivationStrategy</code>, not null
394: */
395: public void setMappingDerivationStrategy(
396: MappingDerivationStrategy mappingDerivationStrategy) {
397: this .mappingDerivationStrategy = mappingDerivationStrategy;
398: }
399:
400: /**
401: * Gets the strategy which determines the properties to be ignored.
402: * @since 0.7
403: * @return the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
404: */
405: public PropertySuppressionStrategy getPropertySuppressionStrategy() {
406: return propertySuppressionStrategy;
407: }
408:
409: /**
410: * Sets the strategy which determines the properties to be ignored.
411: * @since 0.7
412: * @param propertySuppressionStrategy the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
413: */
414: public void setPropertySuppressionStrategy(
415: PropertySuppressionStrategy propertySuppressionStrategy) {
416: this .propertySuppressionStrategy = propertySuppressionStrategy;
417: }
418:
419: /**
420: * Gets the strategy used to determine which types are collective.
421: * @return <code>CollectiveTypeStrategy</code>, not null
422: * @since 0.8
423: */
424: public CollectiveTypeStrategy getCollectiveTypeStrategy() {
425: return collectiveTypeStrategy;
426: }
427:
428: /**
429: * Sets the strategy used to determine which types are collective.
430: * @param collectiveTypeStrategy <code>CollectiveTypeStrategy</code>, not null
431: * @since 0.8
432: */
433: public void setCollectiveTypeStrategy(
434: CollectiveTypeStrategy collectiveTypeStrategy) {
435: this .collectiveTypeStrategy = collectiveTypeStrategy;
436: }
437:
438: /**
439: * Is this a loop type class?
440: * @since 0.7
441: * @param type is this <code>Class</code> a loop type?
442: * @return true if the type is a loop type, or if type is null
443: */
444: public boolean isLoopType(Class type) {
445: return getCollectiveTypeStrategy().isCollective(type);
446: }
447:
448: /**
449: * Returns the <code>AttributeSuppressionStrategy</code>.
450: * This is used to suppress attributes, e.g. for versioning.
451: *
452: * @since 0.8
453: * @return the strategy
454: */
455: public AttributeSuppressionStrategy getAttributeSuppressionStrategy() {
456: return attributeSuppressionStrategy;
457: }
458:
459: /**
460: * Sets the <code>AttributeSuppressionStrategy</code>.
461: * This is used to suppress attributes, e.g. for versioning.
462: *
463: * @since 0.8
464: * @param attributeSuppressionStrategy the strategy
465: */
466: public void setAttributeSuppressionStrategy(
467: AttributeSuppressionStrategy attributeSuppressionStrategy) {
468: this .attributeSuppressionStrategy = attributeSuppressionStrategy;
469: }
470:
471: /**
472: * Returns the <code>ElementSuppressionStrategy</code>.
473: * This is used to suppress elements, e.g. for versioning.
474: *
475: * @since 0.8
476: * @return the strategy
477: */
478: public ElementSuppressionStrategy getElementSuppressionStrategy() {
479: return elementSuppressionStrategy;
480: }
481:
482: /**
483: * Sets the <code>ElementSuppressionStrategy</code>.
484: * This is used to suppress elements, e.g. for versioning.
485: *
486: * @since 0.8
487: * @param elementSuppressionStrategy the strategy
488: */
489: public void setElementSuppressionStrategy(
490: ElementSuppressionStrategy elementSuppressionStrategy) {
491: this.elementSuppressionStrategy = elementSuppressionStrategy;
492: }
493: }
|