1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.betwixt.io;
17
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.Map;
21
22 import org.apache.commons.betwixt.AttributeDescriptor;
23 import org.apache.commons.betwixt.BindingConfiguration;
24 import org.apache.commons.betwixt.ElementDescriptor;
25 import org.apache.commons.betwixt.TextDescriptor;
26 import org.apache.commons.betwixt.XMLBeanInfo;
27 import org.apache.commons.betwixt.XMLIntrospector;
28 import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
29 import org.apache.commons.betwixt.expression.Context;
30 import org.apache.commons.betwixt.expression.MethodUpdater;
31 import org.apache.commons.betwixt.expression.Updater;
32 import org.apache.commons.betwixt.io.read.ElementMapping;
33 import org.apache.commons.betwixt.io.read.ReadConfiguration;
34 import org.apache.commons.betwixt.io.read.ReadContext;
35 import org.apache.commons.digester.Digester;
36 import org.apache.commons.digester.Rule;
37 import org.apache.commons.digester.RuleSet;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.xml.sax.Attributes;
41
42 /*** <p>Sets <code>Betwixt</code> digestion rules for a bean class.</p>
43 *
44 * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
45 * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
46 * @since 0.5
47 */
48 public class BeanRuleSet implements RuleSet {
49
50
51 /*** Logger */
52 private static Log log = LogFactory.getLog( BeanRuleSet.class );
53
54 /***
55 * Set log to be used by <code>BeanRuleSet</code> instances
56 * @param aLog the <code>Log</code> implementation for this class to log to
57 */
58 public static void setLog(Log aLog) {
59 log = aLog;
60 }
61
62 /*** Use this to introspect beans */
63 private XMLIntrospector introspector;
64 /*** The base path under which the rules will be attached */
65 private String basePath;
66 /*** The element descriptor for the base */
67 private ElementDescriptor baseElementDescriptor;
68 /*** The bean based */
69 private Class baseBeanClass;
70 /*** The (empty) base context from which all Contexts
71 with beans are (directly or indirectly) obtained */
72 private ReadContext baseContext;
73 /*** allows an attribute to be specified to overload the types of beans used */
74 private String classNameAttribute = "className";
75
76 /***
77 * Base constructor.
78 *
79 * @param introspector the <code>XMLIntrospector</code> used to introspect
80 * @param basePath specifies the (Digester-style) path under which the rules will be attached
81 * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
82 * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
83 * @param matchIDs should ID/IDREFs be used to match beans?
84 * @deprecated 0.5 use constructor which takes a ReadContext instead
85 */
86 public BeanRuleSet(
87 XMLIntrospector introspector,
88 String basePath,
89 ElementDescriptor baseElementDescriptor,
90 Class baseBeanClass,
91 boolean matchIDs) {
92 this.introspector = introspector;
93 this.basePath = basePath;
94 this.baseElementDescriptor = baseElementDescriptor;
95 this.baseBeanClass = baseBeanClass;
96 BindingConfiguration bindingConfiguration = new BindingConfiguration();
97 bindingConfiguration.setMapIDs( matchIDs );
98 baseContext = new ReadContext( log , bindingConfiguration, new ReadConfiguration() );
99 }
100
101 /***
102 * Base constructor.
103 *
104 * @param introspector the <code>XMLIntrospector</code> used to introspect
105 * @param basePath specifies the (Digester-style) path under which the rules will be attached
106 * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
107 * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
108 * @param context the root Context that bean carrying Contexts should be obtained from,
109 * not null
110 * @deprecated 0.5 use the constructor which takes a ReadContext instead
111 */
112 public BeanRuleSet(
113 XMLIntrospector introspector,
114 String basePath,
115 ElementDescriptor baseElementDescriptor,
116 Class baseBeanClass,
117 Context context) {
118 this.introspector = introspector;
119 this.basePath = basePath;
120 this.baseElementDescriptor = baseElementDescriptor;
121 this.baseBeanClass = baseBeanClass;
122 this.baseContext = new ReadContext( context, new ReadConfiguration() );
123 }
124
125 /***
126 * Base constructor.
127 *
128 * @param introspector the <code>XMLIntrospector</code> used to introspect
129 * @param basePath specifies the (Digester-style) path under which the rules will be attached
130 * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
131 * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
132 * @param baseContext the root Context that bean carrying Contexts should be obtained from,
133 * not null
134 */
135 public BeanRuleSet(
136 XMLIntrospector introspector,
137 String basePath,
138 ElementDescriptor baseElementDescriptor,
139 Class baseBeanClass,
140 ReadContext baseContext) {
141 this.introspector = introspector;
142 this.basePath = basePath;
143 this.baseElementDescriptor = baseElementDescriptor;
144 this.baseBeanClass = baseBeanClass;
145 this.baseContext = baseContext;
146 }
147
148 /***
149 * The name of the attribute which can be specified in the XML to override the
150 * type of a bean used at a certain point in the schema.
151 *
152 * <p>The default value is 'className'.</p>
153 *
154 * @return The name of the attribute used to overload the class name of a bean
155 */
156 public String getClassNameAttribute() {
157 return baseContext.getClassNameAttribute();
158 }
159
160 /***
161 * Sets the name of the attribute which can be specified in
162 * the XML to override the type of a bean used at a certain
163 * point in the schema.
164 *
165 * <p>The default value is 'className'.</p>
166 *
167 * @param classNameAttribute The name of the attribute used to overload the class name of a bean
168 * @deprecated 0.5 set the <code>ReadContext</code> property instead
169 */
170 public void setClassNameAttribute(String classNameAttribute) {
171 baseContext.setClassNameAttribute(classNameAttribute);
172 }
173
174
175
176 /***
177 * <p>Return namespace associated with this ruleset</p>
178 *
179 * <p><strong>Note</strong> namespaces are not currently supported.</p>
180 *
181 * @return null
182 */
183 public String getNamespaceURI() {
184 return null;
185 }
186
187 /***
188 * Add rules for bean to given <code>Digester</code>.
189 *
190 * @param digester the <code>Digester</code> to which the rules for the bean will be added
191 */
192 public void addRuleInstances(Digester digester) {
193 if (log.isTraceEnabled()) {
194 log.trace("Adding rules to:" + digester);
195 }
196
197 ReadingContext readContext = new ReadingContext( digester );
198 }
199
200 /***
201 * <p>A set of associated rules that maps a bean graph.
202 * An instance will be created each time {@link #addRuleInstances} is called.</p>
203 *
204 * <p>When an instance is constructed, rules are created and added to digester.</p>
205 */
206 private class ReadingContext {
207
208 /*** The rules in this context indexed by path */
209 private Map rulesByPath = new HashMap();
210
211 /***
212 * Creates rules for bean and adds them to digester
213 * @param digester the <code>Digester</code>
214 * to which the bean mapping rules will be added
215 */
216 ReadingContext(Digester digester) {
217 ReadContext context = new ReadContext( baseContext );
218
219 if ( context.getClassLoader() == null ) {
220 context.setClassLoader( digester.getClassLoader() );
221 }
222 BeanRule rule
223 = new BeanRule( basePath + "/" , baseElementDescriptor, baseBeanClass, context );
224 addRule( basePath, rule , baseElementDescriptor, context );
225
226 if ( log.isDebugEnabled() ) {
227 log.debug( "Added root rule to path: " + basePath + " class: " + baseBeanClass );
228 }
229
230
231 Iterator it = rulesByPath.entrySet().iterator();
232 while (it.hasNext()) {
233 Map.Entry entry = (Map.Entry) it.next();
234 if ( log.isTraceEnabled() ) {
235 log.trace("Added rule:" + entry.getValue() + " @path:" + entry.getKey());
236 }
237 digester.addRule( (String) entry.getKey() , (Rule) entry.getValue() );
238 }
239 }
240
241 /***
242 * Add child rules for given descriptor at given prefix
243 *
244 * @param prefix add child rules at this (digester) path prefix
245 * @param currentDescriptor add child rules for this descriptor
246 * @param context the <code>Context</code> against which beans will be evaluated
247 */
248 private void addChildRules(
249 String prefix,
250 ElementDescriptor currentDescriptor,
251 ReadContext context ) {
252
253 if (log.isTraceEnabled()) {
254 log.trace("Adding child rules for " + currentDescriptor + "@" + prefix);
255 }
256
257
258
259
260 ElementDescriptor typeDescriptor = getElementDescriptor( currentDescriptor );
261
262
263
264 ElementDescriptor[] childDescriptors = typeDescriptor.getElementDescriptors();
265 if ( childDescriptors != null ) {
266 for ( int i = 0, size = childDescriptors.length; i < size; i++ ) {
267 final ElementDescriptor childDescriptor = childDescriptors[i];
268 if (log.isTraceEnabled()) {
269 log.trace("Processing child " + childDescriptor);
270 }
271
272 String qualifiedName = childDescriptor.getQualifiedName();
273 if ( qualifiedName == null ) {
274 log.trace( "Ignoring" );
275 continue;
276 }
277 String path = prefix + qualifiedName;
278
279
280
281 if ( qualifiedName.equals( currentDescriptor.getQualifiedName() )
282 && currentDescriptor.getPropertyName() != null ) {
283 log.trace("Creating generic rule for recursive elements");
284 int index = -1;
285 if (childDescriptor.isWrapCollectionsInElement()) {
286 index = prefix.indexOf(qualifiedName);
287 if (index == -1) {
288
289 log.debug( "Oops - this shouldn't happen" );
290 continue;
291 }
292 int removeSlash = prefix.endsWith("/")?1:0;
293 path = "*/" + prefix.substring(index, prefix.length()-removeSlash);
294 if (log.isTraceEnabled()) {
295 log.trace("Added wrapped rule for " + childDescriptor);
296 }
297 } else {
298
299 ElementDescriptor[] desc = currentDescriptor.getElementDescriptors();
300 if (desc.length == 1) {
301 path = "*/"+desc[0].getQualifiedName();
302 }
303 if (log.isTraceEnabled()) {
304 log.trace("Added not wrapped rule for " + childDescriptor);
305 }
306 }
307 addRule( path, childDescriptor, context );
308 continue;
309 }
310 if ( childDescriptor.getUpdater() != null ) {
311 if (
312 log.isTraceEnabled()
313 && childDescriptor.getUpdater() instanceof MethodUpdater) {
314
315 log.trace("Element has updater "
316 + ((MethodUpdater) childDescriptor.getUpdater()).getMethod().getName());
317 }
318 if ( childDescriptor.isPrimitiveType() ) {
319 addPrimitiveTypeRule( path, childDescriptor, context );
320
321 } else {
322
323 ElementDescriptor[] grandChildren
324 = childDescriptor.getElementDescriptors();
325 if ( grandChildren != null && grandChildren.length > 0 ) {
326 ElementDescriptor grandChild = grandChildren[0];
327 String grandChildQName = grandChild.getQualifiedName();
328 if ( grandChildQName != null && grandChildQName.length() > 0 ) {
329 if (childDescriptor.isWrapCollectionsInElement()) {
330 path += '/' + grandChildQName;
331 if (log.isTraceEnabled()) {
332 log.trace(
333 "Descriptor wraps elements in collection, path:"
334 + path);
335 }
336
337 } else {
338 path = prefix
339 + (prefix.endsWith("/")?"":"/") + grandChildQName;
340 if (log.isTraceEnabled()) {
341 log.trace(
342 "Descriptor does not wrap elements in collection, path:"
343 + path);
344 }
345 }
346 }
347 }
348
349
350 Class beanClass = childDescriptor.getSingularPropertyType();
351 if ( XMLIntrospectorHelper.isPrimitiveType( beanClass ) ) {
352 addPrimitiveTypeRule( path, childDescriptor, context );
353
354 } else {
355 addRule( path, childDescriptor, context );
356 }
357 }
358 } else {
359 if ( log.isTraceEnabled() ) {
360 log.trace("Element does not have updater: " + childDescriptor);
361 }
362 if (childDescriptor.hasAttributes()) {
363 if ( log.isTraceEnabled() ) {
364 log.trace( "Element has attributes, so adding rule anyway : "
365 + childDescriptor );
366 }
367 addRule(path,childDescriptor, context);
368 }
369 }
370
371 ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors();
372 if ( grandChildren != null && grandChildren.length > 0 ) {
373 if ( log.isTraceEnabled() ) {
374 log.trace("Adding grand children @path:" + path);
375 }
376 addChildRules( path + '/', childDescriptor, context );
377 } else if ( log.isTraceEnabled() ) {
378 log.trace( "No children for " + childDescriptor);
379 }
380 }
381 }
382 }
383
384 /*** Allows the navigation from a reference to a property object to the
385 * descriptor defining what the property is. i.e. doing the join from a reference
386 * to a type to lookup its descriptor.
387 * This could be done automatically by the NodeDescriptors.
388 * Refer to TODO.txt for more info.
389 *
390 * @param propertyDescriptor find descriptor for property object
391 * referenced by this descriptor
392 * @return descriptor for the singular property class type referenced.
393 */
394 ElementDescriptor getElementDescriptor( ElementDescriptor propertyDescriptor ) {
395 Class beanClass = propertyDescriptor.getSingularPropertyType();
396 if ( beanClass != null && !Map.class.isAssignableFrom( beanClass ) ) {
397 if (log.isTraceEnabled()) {
398 log.trace("Filling descriptor for: " + beanClass);
399 }
400 try {
401 XMLBeanInfo xmlInfo = introspector.introspect( beanClass );
402 if (log.isTraceEnabled()) {
403 log.trace("Is wrapped? "
404 + xmlInfo.getElementDescriptor().isWrapCollectionsInElement());
405 }
406 return xmlInfo.getElementDescriptor();
407
408 } catch (Exception e) {
409 log.warn( "Could not introspect class: " + beanClass, e );
410 }
411 }
412
413 return propertyDescriptor;
414 }
415
416 /***
417 * Adds a new Digester rule to process the text as a primitive type
418 *
419 * @param path digester path where this rule will be attached
420 * @param childDescriptor update this <code>ElementDescriptor</code> with the body text
421 * @param context the <code>ReadContext</code> against which the elements will be evaluated
422 */
423 void addPrimitiveTypeRule(
424 String path,
425 final ElementDescriptor childDescriptor,
426 final ReadContext context) {
427
428 Rule rule = new Rule() {
429 public void body(String text) throws Exception {
430 childDescriptor.getUpdater().update( context, text );
431 }
432 };
433 add( path, rule );
434 }
435
436 /***
437 * Adds a new Digester rule to process the text as a primitive type
438 *
439 * @param path digester path where this rule will be attached
440 * @param elementDescriptor update this <code>ElementDescriptor</code> with the body text
441 * @param context the <code>ReadContext</code> against which the elements will be evaluated
442 */
443 private void addRule(
444 String path,
445 ElementDescriptor elementDescriptor,
446 ReadContext context ) {
447 BeanRule rule = new BeanRule( path + '/', elementDescriptor, context );
448 addRule( path, rule, elementDescriptor, context );
449 }
450
451 /***
452 * Safely add a rule with given path.
453 *
454 * @param path the digester path to add rule at
455 * @param rule the <code>Rule</code> to add
456 * @param elementDescriptor the <code>ElementDescriptor</code>
457 * associated with this rule
458 * @param context the <code>ReadContext</code> against which the elements
459 * will be evaluated
460 */
461 private void addRule(
462 String path,
463 Rule rule,
464 ElementDescriptor elementDescriptor,
465 ReadContext context) {
466 if ( add( path, rule ) ) {
467
468 addChildRules( path + '/', elementDescriptor, context );
469 }
470 }
471
472 /***
473 * Add a rule at given path.
474 *
475 * @param path add rule at this path
476 * @param rule the <code>Rule</code> to add
477 *
478 * @return true if this rule was successfully add at given path
479 */
480 private boolean add( String path, Rule rule ) {
481
482 if ( ! rulesByPath.containsKey( path ) ) {
483 if ( log.isDebugEnabled() ) {
484 log.debug( "Added rule for path: " + path + " rule: " + rule );
485 if (log.isTraceEnabled()) {
486 log.trace( rulesByPath );
487 }
488 }
489 rulesByPath.put( path, rule );
490 return true;
491
492 } else {
493 if ( log.isDebugEnabled() ) {
494 log.debug( "Ignoring duplicate digester rule for path: "
495 + path + " rule: " + rule );
496 log.debug( "New rule (not added): " + rule );
497 log.debug( "Existing rule:" + rulesByPath.get(path) );
498 }
499 }
500 return false;
501 }
502
503 /***
504 * Rule that creates bean and updates methods.
505 */
506 private class BeanRule extends Rule {
507
508 /*** The descriptor of this element */
509 private ElementDescriptor descriptor;
510 /*** The Context used when evaluating Updaters */
511 private ReadContext context;
512 /*** In this begin-end loop did we actually create a new bean */
513 private boolean createdBean;
514 /*** The type of the bean to create */
515 private Class beanClass;
516 /*** The prefix added to digester rules */
517 private String pathPrefix;
518
519
520 /***
521 * Constructor uses standard qualified name from <code>ElementDescriptor</code>.
522 *
523 * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
524 * @param beanClass the <code>Class</code> to be created
525 * @param context the <code>ReadContext</code> for this rule
526 */
527 public BeanRule( ElementDescriptor descriptor, Class beanClass, ReadContext context ) {
528 this( descriptor.getQualifiedName() + "/", descriptor, beanClass, context );
529 }
530
531 /***
532 * Construct a rule based on singular property type of <code>ElementDescriptor</code>.
533 *
534 * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
535 * @param context the <code>Context</code> to be used to evaluate expressions
536 * @param pathPrefix the digester path prefix
537 */
538 public BeanRule(
539 String pathPrefix,
540 ElementDescriptor descriptor,
541 ReadContext context ) {
542 this(
543 pathPrefix,
544 descriptor,
545 descriptor.getSingularPropertyType(),
546 context );
547 }
548
549 /***
550 * Base constructor (used by other constructors).
551 *
552 * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
553 * @param beanClass the <code>Class</code> of the bean to be created
554 * @param context the <code>Context</code> to be used to evaluate expressions
555 * @param pathPrefix the digester path prefix
556 */
557 private BeanRule(
558 String pathPrefix,
559 ElementDescriptor descriptor,
560 Class beanClass,
561 ReadContext context ) {
562 this.descriptor = descriptor;
563 this.context = context;
564 this.beanClass = beanClass;
565 this.pathPrefix = pathPrefix;
566
567 if (log.isTraceEnabled()) {
568 log.trace("Created bean create rule");
569 log.trace("Descriptor=" + descriptor);
570 log.trace("Class=" + beanClass);
571 log.trace("Path prefix=" + pathPrefix);
572 }
573 }
574
575
576
577
578 /***
579 * @see Rule#begin(String, String, Attributes)
580 */
581 public void begin(String namespace, String name, Attributes attributes) {
582 if ( log.isDebugEnabled() ) {
583 log.debug( "Called with descriptor: " + descriptor
584 + " propertyType: " + descriptor.getPropertyType() );
585 }
586
587 if (log.isTraceEnabled()) {
588 int attributesLength = attributes.getLength();
589 if (attributesLength > 0) {
590 log.trace("Attributes:");
591 }
592 for (int i=0, size=attributesLength; i<size; i++) {
593 log.trace("Local:" + attributes.getLocalName(i));
594 log.trace("URI:" + attributes.getURI(i));
595 log.trace("QName:" + attributes.getQName(i));
596 }
597 }
598
599
600
601
602 createdBean = false;
603 Object instance = null;
604
605
606
607
608 ElementDescriptor typeDescriptor = getElementDescriptor( descriptor );
609 if ( typeDescriptor.getUpdater() == null && beanClass == null ) {
610
611 instance = context.getBean();
612 if ( instance == null ) {
613 return;
614 }
615 } else {
616 instance = createBean( namespace, name, attributes );
617 if ( instance != null ) {
618 createdBean = true;
619 context.setBean( instance );
620 digester.push( instance );
621 } else {
622
623 return;
624 }
625 }
626
627
628 AttributeDescriptor[] attributeDescriptors
629 = typeDescriptor.getAttributeDescriptors();
630 if ( attributeDescriptors != null ) {
631 for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
632 AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
633
634
635
636
637
638 String value = attributes.getValue(
639 attributeDescriptor.getURI(),
640 attributeDescriptor.getLocalName()
641 );
642
643 if ( value == null ) {
644 value = attributes.getValue(
645 attributeDescriptor.getQualifiedName());
646 }
647
648 if ( log.isTraceEnabled() ) {
649 log.trace("Attr URL:" + attributeDescriptor.getURI());
650 log.trace(
651 "Attr LocalName:"
652 + attributeDescriptor.getLocalName() );
653 log.trace(value);
654 }
655
656 Updater updater = attributeDescriptor.getUpdater();
657 if ( log.isTraceEnabled() ) {
658 log.trace("Updater : "+updater);
659 }
660 if ( updater != null && value != null ) {
661 updater.update( context, value );
662 }
663 }
664 }
665
666 if ( log.isTraceEnabled() ) {
667 log.trace("Created bean " + instance);
668 log.trace("Path prefix: " + pathPrefix);
669 }
670
671
672 if ( context.getMapIDs() ) {
673
674
675
676 String id = attributes.getValue( "id" );
677 if ( id != null ) {
678 context.putBean( id, instance );
679 }
680 }
681 }
682
683 /***
684 * @see Rule#body(String, String, String)
685 */
686 public void body(String namespace, String name, String text) {
687
688 if ( log.isTraceEnabled() ) {
689 log.trace("Body with text " + text);
690 }
691 if ( digester.getCount() > 0 ) {
692 Context bodyContext = context.newContext( digester.peek() );
693
694 ElementDescriptor typeDescriptor = getElementDescriptor( descriptor );
695 TextDescriptor descriptor = typeDescriptor.getPrimaryBodyTextDescriptor();
696 if ( descriptor != null ) {
697 if ( log.isTraceEnabled() ) {
698 log.trace("Setting mixed content for:");
699 log.trace(descriptor);
700 }
701 Updater updater = descriptor.getUpdater();
702 if ( log.isTraceEnabled() ) {
703 log.trace( "Updating mixed content with:" );
704 log.trace( updater );
705 }
706 if ( updater != null && text != null ) {
707 updater.update( bodyContext, text );
708 }
709 }
710 }
711 }
712
713 /***
714 * Process the end of this element.
715 */
716 public void end() {
717 if ( createdBean ) {
718
719
720 Updater updater = descriptor.getUpdater();
721 Object instance = context.getBean();
722
723 Object top = digester.pop();
724 if (log.isTraceEnabled()) {
725 log.trace("Popped " + top);
726 }
727 if (digester.getCount() == 0) {
728 context.setBean(null);
729 }else{
730 context.setBean( digester.peek() );
731 }
732
733 if ( updater != null ) {
734 if ( log.isDebugEnabled() ) {
735 log.debug( "Calling updater for: " + descriptor + " with: "
736 + instance + " on bean: " + context.getBean() );
737 }
738 updater.update( context, instance );
739 } else {
740 if ( log.isDebugEnabled() ) {
741 log.debug( "No updater for: " + descriptor + " with: "
742 + instance + " on bean: " + context.getBean() );
743 }
744 }
745 }
746 }
747
748 /***
749 * Tidy up.
750 */
751 public void finish() {
752
753
754
755 baseContext.clearBeans();
756 }
757
758
759
760
761
762 /***
763 * Factory method to create new bean instances
764 *
765 * @param namespace the namespace for the element
766 * @param name the local name
767 * @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
768 * @return the created bean
769 */
770 protected Object createBean( String namespace, String name, Attributes attributes ) {
771
772 ElementMapping mapping = new ElementMapping();
773 mapping.setType( beanClass );
774 mapping.setNamespace( namespace );
775 mapping.setName( name );
776 mapping.setAttributes( attributes );
777 mapping.setDescriptor( descriptor );
778
779 Object newInstance = context.getBeanCreationChain().create( mapping, context );
780
781 return newInstance;
782 }
783
784 /***
785 * Return something meaningful for logging.
786 *
787 * @return something useful for logging
788 */
789 public String toString() {
790 return "BeanRule [path prefix=" + pathPrefix + " descriptor=" + descriptor + "]";
791 }
792 }
793 }
794 }
795