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 }