KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xml > binding > MappingObjectModelFactory


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.xml.binding;
8
9 import org.jboss.logging.Logger;
10 import org.jboss.util.Classes;
11 import org.jboss.util.NestedRuntimeException;
12 import org.xml.sax.Attributes JavaDoc;
13 import org.apache.xerces.xs.XSTypeDefinition;
14
15 import java.lang.reflect.Method JavaDoc;
16 import java.lang.reflect.Constructor JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.List JavaDoc;
22
23 /**
24  * An ObjectModelFactory that uses mappings
25  *
26  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
27  * @author <a HREF="mailto:adrian@jboss.com">Adrian Brock</a>
28  * @version <tt>$Revision: 1.1.2.6 $</tt>
29  */

30 public class MappingObjectModelFactory
31    implements GenericObjectModelFactory
32 {
33    private final static Logger log = Logger.getLogger(MappingObjectModelFactory.class);
34
35    /**
36     * The class mappings
37     */

38    private final Map JavaDoc elementToClassMapping = new HashMap JavaDoc();
39
40    /**
41     * The field mappings
42     */

43    private final Map JavaDoc elementToFieldMapping = new HashMap JavaDoc();
44
45    // Public
46

47    /**
48     * Map an element to a class
49     *
50     * @param element the element name
51     * @param cls the class
52     */

53    public void mapElementToClass(String JavaDoc element, Class JavaDoc cls)
54    {
55       ElementToClassMapping mapping = new ElementToClassMapping(element, cls);
56       addElementToClassMapping(mapping);
57       if(log.isTraceEnabled())
58       {
59          log.trace(mapping);
60       }
61    }
62
63    /**
64     * Map an element to a field
65     *
66     * @param element the element name
67     * @param cls the class
68     * @param field the field name
69     * @param converter the type convertor
70     */

71    public void mapElementToField(String JavaDoc element, Class JavaDoc cls, String JavaDoc field, TypeConverter converter)
72    {
73       ElementToFieldMapping mapping = new ElementToFieldMapping(element, cls, field, converter);
74       addElementToFieldMapping(mapping);
75       if(log.isTraceEnabled())
76       {
77          log.trace(mapping);
78       }
79    }
80
81    // ObjectModelFactory implementation
82

83    public Object JavaDoc newRoot(Object JavaDoc root,
84                          ContentNavigator navigator,
85                          String JavaDoc namespaceURI,
86                          String JavaDoc localName,
87                          Attributes JavaDoc attrs)
88    {
89       if(log.isTraceEnabled())
90       {
91          log.trace("newRoot root=" +
92             root +
93             " navigator=" +
94             navigator +
95             " namespaceURI=" +
96             namespaceURI +
97             " localName=" +
98             localName +
99             " attributes=" +
100             attrs
101          );
102       }
103
104       if(root == null)
105       {
106          ElementToClassMapping mapping = (ElementToClassMapping)elementToClassMapping.get(localName);
107          if(mapping != null)
108          {
109             if(log.isTraceEnabled())
110             {
111                log.trace("creating root using " + mapping);
112             }
113             root = newInstance(mapping.cls);
114          }
115          else
116          {
117             root = create(namespaceURI, localName, navigator.getType());
118          }
119
120          if(root == null)
121          {
122             throw new IllegalStateException JavaDoc(
123                "Failed to resolve Java type binding for root element: ns=" + namespaceURI + ", local=" + localName
124             );
125          }
126       }
127
128       if(attrs != null)
129       {
130          for(int i = 0; i < attrs.getLength(); ++i)
131          {
132             try
133             {
134                if(attrs.getLocalName(i).length() > 0)
135                {
136                   if(!attrs.getQName(i).startsWith("xsi:")) //todo horrible
137
{
138                      setAttribute(root, attrs.getLocalName(i), attrs.getValue(i), navigator.getType());
139                   }
140                }
141             }
142             catch(Exception JavaDoc e)
143             {
144                String JavaDoc msg = "Failed to set attribute " + attrs.getQName(i) + "=" + attrs.getValue(i);
145                log.error(msg, e);
146                throw new IllegalStateException JavaDoc(msg + ": " + e.getMessage());
147             }
148          }
149       }
150
151       return root;
152    }
153
154    // GenericObjectModelFactory implementation
155

156    public Object JavaDoc newChild(Object JavaDoc o,
157                           ContentNavigator navigator,
158                           String JavaDoc namespaceURI,
159                           String JavaDoc localName,
160                           Attributes JavaDoc attrs)
161    {
162       if(log.isTraceEnabled())
163       {
164          log.trace("newChild object=" +
165             o +
166             " navigator=" +
167             navigator +
168             " namespaceURI=" +
169             namespaceURI +
170             " localName=" +
171             localName +
172             " attributes=" +
173             attrs
174          );
175       }
176
177       if(o == null)
178       {
179          throw new RuntimeException JavaDoc("Attempt to add a new child to a null parent localName=" + localName);
180       }
181
182       Object JavaDoc child = null;
183
184       ElementToClassMapping mapping = (ElementToClassMapping)elementToClassMapping.get(localName);
185       XSTypeDefinition type = navigator.getType();
186       if(mapping != null)
187       {
188          if(log.isTraceEnabled())
189          {
190             log.trace("newChild using mapping " + mapping);
191          }
192
193          try
194          {
195             if(!(o instanceof Collection JavaDoc))
196             {
197                Method JavaDoc getter;
198                ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get(
199                   new ElementToFieldMappingKey(localName, o.getClass())
200                );
201
202                if(fieldMapping != null)
203                {
204                   getter = fieldMapping.getter;
205                }
206                else
207                {
208                   String JavaDoc getterStr = Util.xmlNameToGetMethodName(localName, true);
209                   getter = o.getClass().getMethod(getterStr, null);
210                }
211                child = get(o, localName, getter);
212             }
213
214             if(child == null)
215             {
216                child = newInstance(mapping.cls);
217             }
218
219             if(attrs != null)
220             {
221                for(int i = 0; i < attrs.getLength(); ++i)
222                {
223                   if(attrs.getLocalName(i).length() > 0)
224                   {
225                      if(!attrs.getQName(i).startsWith("xsi:")) //todo horrible
226
{
227                         setAttribute(child, attrs.getLocalName(i), attrs.getValue(i), type);
228                      }
229                   }
230                }
231             }
232          }
233          catch(IllegalStateException JavaDoc e)
234          {
235             throw e;
236          }
237          catch(Exception JavaDoc e)
238          {
239             throw new NestedRuntimeException("newChild failed for o=" +
240                o +
241                ", uri=" +
242                namespaceURI +
243                ", local="
244                + localName + ", attrs=" + attrs, e
245             );
246          }
247       }
248       else
249       {
250          if(o instanceof Collection JavaDoc)
251          {
252             child = create(namespaceURI, localName, type);
253          }
254          else
255          {
256             Class JavaDoc oCls;
257             if(o instanceof ImmutableContainer)
258             {
259                oCls = ((ImmutableContainer)o).cls;
260             }
261             else
262             {
263                oCls = o.getClass();
264             }
265
266             String JavaDoc getterStr = Util.xmlNameToGetMethodName(localName, true);
267             Method JavaDoc getter;
268             try
269             {
270                getter = oCls.getMethod(getterStr, null);
271             }
272             catch(NoSuchMethodException JavaDoc e)
273             {
274                throw new IllegalStateException JavaDoc("newChild failed for o=" +
275                   o +
276                   ", uri=" +
277                   namespaceURI +
278                   ", local="
279                   + localName + ", attrs=" + attrs + ": no getter"
280                );
281             }
282
283             Class JavaDoc childType = getter.getReturnType();
284             if(Collection JavaDoc.class.isAssignableFrom(childType))
285             {
286                child = get(o, localName, getter);
287
288                // now does this element really represent a Java collection or is it an element that can appear more than once?
289
// try to load the class and create an instance
290
Object JavaDoc item = null;
291                if(type == null || type != null && type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
292                {
293                   item = create(namespaceURI, localName, type);
294                }
295
296                if(item != null)
297                {
298                   if(child == null)
299                   {
300                      setChild(new ArrayList JavaDoc(), o, localName);
301                   }
302                   child = item;
303                }
304                else
305                {
306                   if(child == null)
307                   {
308                      child = new ArrayList JavaDoc();
309                   }
310                }
311             }
312             else if(!Util.isAttributeType(childType))
313             {
314                // id there is no field mapping
315
ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get(
316                   new ElementToFieldMappingKey(localName, o.getClass())
317                );
318                TypeConverter converter = fieldMapping == null ? null : fieldMapping.converter;
319
320                // if converter != null it will be used in setValue
321
if(converter == null)
322                {
323                   child = newInstance(childType);
324                }
325             }
326          }
327       }
328
329       return child;
330    }
331
332    public void addChild(Object JavaDoc parent,
333                         Object JavaDoc child,
334                         ContentNavigator navigator,
335                         String JavaDoc namespaceURI,
336                         String JavaDoc localName)
337    {
338       if(log.isTraceEnabled())
339       {
340          log.trace("addChild parent=" +
341             parent +
342             " child=" +
343             child +
344             " navigator=" +
345             navigator +
346             " namespaceURI=" +
347             namespaceURI +
348             " localName=" +
349             localName
350          );
351       }
352
353       if(child instanceof ImmutableContainer)
354       {
355          child = ((ImmutableContainer)child).newInstance();
356       }
357       setChild(child, parent, localName);
358    }
359
360    public void setValue(Object JavaDoc o, ContentNavigator navigator, String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc value)
361    {
362       if(log.isTraceEnabled())
363       {
364          log.trace("setValue object=" +
365             o +
366             " navigator=" +
367             navigator +
368             " namespaceURI=" +
369             namespaceURI +
370             " localName=" +
371             localName +
372             " value=" +
373             value
374          );
375       }
376
377       setAttribute(o, localName, value, navigator.getType());
378    }
379
380    public Object JavaDoc completedRoot(Object JavaDoc root, ContentNavigator navigator, String JavaDoc namespaceURI, String JavaDoc localName)
381    {
382       if(log.isTraceEnabled())
383       {
384          log.trace("completedRoot root=" +
385             root +
386             " navigator=" +
387             navigator +
388             " namespaceURI=" +
389             namespaceURI +
390             " localName=" +
391             localName
392          );
393       }
394
395       if(root instanceof ImmutableContainer)
396       {
397          root = ((ImmutableContainer)root).newInstance();
398       }
399       return root;
400    }
401
402    // Private
403

404    private void addElementToClassMapping(ElementToClassMapping mapping)
405    {
406       elementToClassMapping.put(mapping.element, mapping);
407    }
408
409    private void addElementToFieldMapping(ElementToFieldMapping mapping)
410    {
411       elementToFieldMapping.put(mapping.key, mapping);
412    }
413
414    private void setChild(Object JavaDoc child, Object JavaDoc parent, String JavaDoc localName)
415    {
416       boolean trace = log.isTraceEnabled();
417       Object JavaDoc value = child;
418       if(parent instanceof Collection JavaDoc)
419       {
420          if(trace)
421          {
422             log.trace("Add " + value + " to collection " + parent);
423          }
424          ((Collection JavaDoc)parent).add(value);
425       }
426       else
427       {
428          Method JavaDoc setter = null;
429          final ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get(
430             new ElementToFieldMappingKey(localName, parent.getClass())
431          );
432          if(fieldMapping != null)
433          {
434             if(trace)
435             {
436                log.trace("Add " + value + " to " + parent + " using field mapping " + fieldMapping);
437             }
438             setter = fieldMapping.setter;
439             set(parent, value, localName, setter);
440          }
441          else
442          {
443             final String JavaDoc xmlToCls = Util.xmlNameToClassName(localName, true);
444             if(trace)
445             {
446                log.trace("Add " + value + " to xml mapped class " + xmlToCls);
447             }
448             Method JavaDoc getter = null;
449             Class JavaDoc parentCls;
450             if(parent instanceof ImmutableContainer)
451             {
452                parentCls = ((ImmutableContainer)parent).cls;
453             }
454             else
455             {
456                parentCls = parent.getClass();
457             }
458
459             try
460             {
461                getter = parentCls.getMethod("get" + xmlToCls, null);
462             }
463             catch(NoSuchMethodException JavaDoc e)
464             {
465                log.warn("no getter found for " + localName + " in " + parent);
466             }
467
468             if(getter != null)
469             {
470                if(!(child instanceof Collection JavaDoc) && Collection JavaDoc.class.isAssignableFrom(getter.getReturnType()))
471                {
472                   Object JavaDoc o = get(parent, localName, getter);
473                   Collection JavaDoc col = (Collection JavaDoc)o;
474                   if(trace)
475                   {
476                      log.trace("Add " + value + " to collection " + col + " retrieved from getter " + getter);
477                   }
478                   col.add(child);
479                }
480                else
481                {
482
483                   try
484                   {
485                      setter = parentCls.getMethod("set" + xmlToCls, new Class JavaDoc[]{getter.getReturnType()});
486                   }
487                   catch(NoSuchMethodException JavaDoc e)
488                   {
489                      log.warn("No setter for " + localName + " in " + parentCls);
490                   }
491
492                   set(parent, value, localName, setter);
493                }
494             }
495          }
496       }
497    }
498
499    private void setAttribute(Object JavaDoc o, String JavaDoc localName, String JavaDoc value, XSTypeDefinition type)
500    {
501       if(o instanceof Collection JavaDoc)
502       {
503          if(type == null)
504          {
505             log.warn("Type is not available for collection item " + localName + "=" + value + " -> adding as string.");
506             ((Collection JavaDoc)o).add(value);
507          }
508          else
509          {
510             if(type.getName() == null)
511             {
512                throw new IllegalStateException JavaDoc("Name is null for simple type?!");
513             }
514
515             Object JavaDoc trgValue = TypeBinding.unmarshal(type.getName(), value);
516             ((Collection JavaDoc)o).add(trgValue);
517          }
518       }
519       else
520       {
521          Method JavaDoc setter = null;
522          Object JavaDoc fieldValue = null;
523          final ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get(
524             new ElementToFieldMappingKey(localName, o.getClass())
525          );
526          if(fieldMapping != null)
527          {
528             fieldValue = fieldMapping.converter.unmarshal(value);
529             setter = fieldMapping.setter;
530          }
531          else
532          {
533             Class JavaDoc oCls;
534             if(o instanceof ImmutableContainer)
535             {
536                oCls = ((ImmutableContainer)o).cls;
537             }
538             else
539             {
540                oCls = o.getClass();
541             }
542
543             try
544             {
545                final String JavaDoc xmlToCls = Util.xmlNameToClassName(localName, true);
546                Method JavaDoc getter = oCls.getMethod("get" + xmlToCls, null);
547                fieldValue = TypeBinding.unmarshal(value, getter.getReturnType());
548                setter = oCls.getMethod("set" + xmlToCls, new Class JavaDoc[]{getter.getReturnType()});
549             }
550             catch(NoSuchMethodException JavaDoc e)
551             {
552                log.warn("no setter found for " + localName + " in " + oCls);
553             }
554          }
555
556          set(o, fieldValue, localName, setter);
557       }
558    }
559
560    /**
561     * Converts namspace URI and local name into a class name, tries to load the class,
562     * create an instance and return it.
563     *
564     * @param namespaceURI element's namespace URI
565     * @param localName element's local name
566     * @return null if the class could not be loaded, otherwise an instance of the loaded class
567     */

568    private static Object JavaDoc create(String JavaDoc namespaceURI, String JavaDoc localName, XSTypeDefinition type)
569    {
570       Object JavaDoc o = null;
571
572       String JavaDoc clsName = type != null && type.getName() != null ?
573          Util.xmlNameToClassName(namespaceURI, type.getName(), true) :
574          Util.xmlNameToClassName(namespaceURI, localName, true);
575
576       Class JavaDoc cls = null;
577       try
578       {
579          cls = Thread.currentThread().getContextClassLoader().loadClass(clsName);
580       }
581       catch(ClassNotFoundException JavaDoc e)
582       {
583          if(log.isTraceEnabled())
584          {
585             log.trace("create: failed to load class " + clsName);
586          }
587       }
588
589       if(cls != null)
590       {
591          o = newInstance(cls);
592       }
593
594       return o;
595    }
596
597    private static Object JavaDoc get(Object JavaDoc o, String JavaDoc localName, Method JavaDoc getter)
598    {
599       if(log.isTraceEnabled())
600       {
601          log.trace("get object=" + o + " localName=" + localName + " getter=" + getter);
602       }
603
604       Object JavaDoc value;
605       if(o instanceof ImmutableContainer)
606       {
607          ImmutableContainer con = ((ImmutableContainer)o);
608          value = con.getChild(localName);
609       }
610       else
611       {
612          try
613          {
614             value = getter.invoke(o, null);
615          }
616          catch(Exception JavaDoc e)
617          {
618             throw new NestedRuntimeException("Failed to invoke " + getter + " on " + o, e);
619          }
620       }
621       return value;
622    }
623
624    private static void set(Object JavaDoc parent, Object JavaDoc child, String JavaDoc localName, Method JavaDoc setter)
625    {
626       if(log.isTraceEnabled())
627       {
628          log.trace("set parent=" + parent + " child=" + child + " localName=" + localName + " setter=" + setter);
629       }
630
631       if(setter != null)
632       {
633          try
634          {
635             setter.invoke(parent, new Object JavaDoc[]{child});
636          }
637          catch(Exception JavaDoc e)
638          {
639             throw new NestedRuntimeException("Failed to set attribute value " +
640                child +
641                " with setter " +
642                setter
643                + " on " + parent + ": ", e
644             );
645          }
646       }
647       else if(parent instanceof ImmutableContainer)
648       {
649          ((ImmutableContainer)parent).addChild(localName, child);
650       }
651       else
652       {
653          throw new IllegalStateException JavaDoc("setter is null and it's not an immutable container: parent=" +
654             parent.getClass() +
655             ", localName" + localName + ", parent=" + parent + ", child=" + child
656          );
657       }
658    }
659
660    private static Object JavaDoc newInstance(Class JavaDoc cls)
661    {
662       if(log.isTraceEnabled())
663       {
664          log.trace("new " + cls.getName());
665       }
666
667       Object JavaDoc instance;
668       try
669       {
670          Constructor JavaDoc ctor = cls.getConstructor(null);
671          instance = ctor.newInstance(null);
672       }
673       catch(NoSuchMethodException JavaDoc e)
674       {
675          log.warn("No no-arg constructor in " + cls);
676          instance = new ImmutableContainer(cls);
677       }
678       catch(Exception JavaDoc e)
679       {
680          throw new IllegalStateException JavaDoc("Failed to create an instance of " +
681             cls +
682             " with the no-arg constructor: "
683             + e.getMessage()
684          );
685       }
686       return instance;
687    }
688
689    // Inner classes
690

691    private class ElementToClassMapping
692    {
693       public final String JavaDoc element;
694
695       public final Class JavaDoc cls;
696
697       public ElementToClassMapping(String JavaDoc element, Class JavaDoc cls)
698       {
699          this.element = element;
700          this.cls = cls;
701       }
702
703       public String JavaDoc toString()
704       {
705          StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
706          buffer.append("ElementToClass@").append(System.identityHashCode(this));
707          buffer.append("{element=").append(element);
708          if(cls != null)
709          {
710             buffer.append(" class=").append(cls.getName());
711          }
712          buffer.append("}");
713          return buffer.toString();
714       }
715
716       public boolean equals(Object JavaDoc o)
717       {
718          if(this == o)
719          {
720             return true;
721          }
722          if(!(o instanceof ElementToClassMapping))
723          {
724             return false;
725          }
726
727          final ElementToClassMapping classMapping = (ElementToClassMapping)o;
728
729          if(cls != null ? !cls.equals(classMapping.cls) : classMapping.cls != null)
730          {
731             return false;
732          }
733
734          return true;
735       }
736
737       public int hashCode()
738       {
739          return (cls != null ? cls.hashCode() : 0);
740       }
741    }
742
743    private class ElementToFieldMappingKey
744    {
745       public final String JavaDoc element;
746
747       public final Class JavaDoc cls;
748
749       public ElementToFieldMappingKey(String JavaDoc element, Class JavaDoc cls)
750       {
751          this.element = element;
752          this.cls = cls;
753       }
754
755       public boolean equals(Object JavaDoc o)
756       {
757          if(this == o)
758          {
759             return true;
760          }
761          if(!(o instanceof ElementToFieldMappingKey))
762          {
763             return false;
764          }
765
766          final ElementToFieldMappingKey elementToFieldMappingKey = (ElementToFieldMappingKey)o;
767
768          if(cls != null ? !cls.equals(elementToFieldMappingKey.cls) : elementToFieldMappingKey.cls != null)
769          {
770             return false;
771          }
772          if(element != null ?
773             !element.equals(elementToFieldMappingKey.element) :
774             elementToFieldMappingKey.element != null)
775          {
776             return false;
777          }
778
779          return true;
780       }
781
782       public int hashCode()
783       {
784          int result;
785          result = (element != null ? element.hashCode() : 0);
786          result = 29 * result + (cls != null ? cls.hashCode() : 0);
787          return result;
788       }
789    }
790
791    private class ElementToFieldMapping
792    {
793       public final String JavaDoc element;
794
795       public final Class JavaDoc cls;
796
797       public final String JavaDoc field;
798
799       public final TypeConverter converter;
800
801       public final ElementToFieldMappingKey key;
802
803       public final Method JavaDoc getter;
804
805       public final Method JavaDoc setter;
806
807       public ElementToFieldMapping(String JavaDoc element, Class JavaDoc cls, String JavaDoc field, TypeConverter converter)
808       {
809          this.element = element;
810          this.cls = cls;
811          this.field = field;
812          this.converter = converter;
813          key = new ElementToFieldMappingKey(element, cls);
814
815          try
816          {
817             getter = Classes.getAttributeGetter(cls, field);
818          }
819          catch(NoSuchMethodException JavaDoc e)
820          {
821             throw new IllegalStateException JavaDoc("Getter not found for " + field + " in class " + cls.getName());
822          }
823
824          try
825          {
826             setter = Classes.getAttributeSetter(cls, field, getter.getReturnType());
827          }
828          catch(NoSuchMethodException JavaDoc e)
829          {
830             throw new IllegalStateException JavaDoc("Setter not found for " + field + " in class " + cls.getName());
831          }
832       }
833
834       public String JavaDoc toString()
835       {
836          StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
837          buffer.append("ElementToField@").append(System.identityHashCode(this));
838          buffer.append("{element=").append(element);
839          if(cls != null)
840          {
841             buffer.append(" class=").append(cls.getName());
842          }
843          buffer.append(" field=").append(field);
844          buffer.append(" getter=").append(getter);
845          buffer.append(" setter=").append(setter);
846          if(converter != null)
847          {
848             buffer.append(" convertor=").append(converter.getClass().getName());
849          }
850          buffer.append("}");
851          return buffer.toString();
852       }
853
854       public boolean equals(Object JavaDoc o)
855       {
856          if(this == o)
857          {
858             return true;
859          }
860          if(!(o instanceof ElementToFieldMapping))
861          {
862             return false;
863          }
864
865          final ElementToFieldMapping elementToFieldMapping = (ElementToFieldMapping)o;
866
867          if(cls != null ? !cls.equals(elementToFieldMapping.cls) : elementToFieldMapping.cls != null)
868          {
869             return false;
870          }
871          if(element != null ? !element.equals(elementToFieldMapping.element) : elementToFieldMapping.element != null)
872          {
873             return false;
874          }
875          if(field != null ? !field.equals(elementToFieldMapping.field) : elementToFieldMapping.field != null)
876          {
877             return false;
878          }
879
880          return true;
881       }
882
883       public int hashCode()
884       {
885          int result;
886          result = (element != null ? element.hashCode() : 0);
887          result = 29 * result + (cls != null ? cls.hashCode() : 0);
888          result = 29 * result + (field != null ? field.hashCode() : 0);
889          return result;
890       }
891    }
892
893    private static class ImmutableContainer
894    {
895       private final Class JavaDoc cls;
896
897       private final List JavaDoc names = new ArrayList JavaDoc();
898
899       private final List JavaDoc values = new ArrayList JavaDoc();
900
901       public ImmutableContainer(Class JavaDoc cls)
902       {
903          this.cls = cls;
904          if(log.isTraceEnabled())
905          {
906             log.trace("created immutable container for " + cls);
907          }
908       }
909
910       public void addChild(String JavaDoc localName, Object JavaDoc child)
911       {
912          if(!names.isEmpty() && names.get(names.size() - 1).equals(localName))
913          {
914             throw new IllegalStateException JavaDoc("Attempt to add duplicate element " + localName);
915          }
916          names.add(localName);
917          values.add(child);
918
919          if(log.isTraceEnabled())
920          {
921             log.trace("added child " + localName + " for " + cls + ": " + child);
922          }
923       }
924
925       public Object JavaDoc getChild(String JavaDoc localName)
926       {
927          return names.get(names.size() - 1).equals(localName) ? values.get(values.size() - 1) : null;
928       }
929
930       public Object JavaDoc[] getValues()
931       {
932          return values.toArray();
933       }
934
935       public Class JavaDoc[] getValueTypes()
936       {
937          Class JavaDoc[] types = new Class JavaDoc[values.size()];
938          for(int i = 0; i < values.size(); ++i)
939          {
940             types[i] = values.get(i).getClass();
941          }
942          return types;
943       }
944
945       public Object JavaDoc newInstance()
946       {
947          Constructor JavaDoc ctor = null;
948          Constructor JavaDoc[] ctors = cls.getConstructors();
949
950          if(ctors == null || ctors.length == 0)
951          {
952             throw new JBossXBRuntimeException("The class has no declared constructors: " + cls);
953          }
954
955          for(int i = 0; i < ctors.length; ++i)
956          {
957             Class JavaDoc[] types = ctors[i].getParameterTypes();
958
959             if(types == null || types.length == 0)
960             {
961                throw new IllegalStateException JavaDoc("Found no-arg constructor for immutable " + cls);
962             }
963
964             if(types.length == values.size())
965             {
966                ctor = ctors[i];
967
968                int typeInd = 0;
969                while(typeInd < types.length)
970                {
971                   if(!types[typeInd].isAssignableFrom(values.get(typeInd++).getClass()))
972                   {
973                      ctor = null;
974                      break;
975                   }
976                }
977
978                if(ctor != null)
979                {
980                   break;
981                }
982             }
983          }
984
985          if(ctor == null)
986          {
987             throw new IllegalStateException JavaDoc("No constructor in " + cls + " that would take arguments " + values);
988          }
989
990          try
991          {
992             return ctor.newInstance(values.toArray());
993          }
994          catch(Exception JavaDoc e)
995          {
996             throw new IllegalStateException JavaDoc("Failed to create immutable instance of " +
997                cls +
998                " using arguments: "
999                + values + ": " + e.getMessage()
1000            );
1001         }
1002      }
1003   }
1004}
1005
Popular Tags