KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xb > binding > metadata > unmarshalling > impl > DocumentBindingFactoryImpl


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.xb.binding.metadata.unmarshalling.impl;
8
9 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBindingFactory;
10 import org.jboss.xb.binding.metadata.unmarshalling.NamespaceBinding;
11 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinding;
12 import org.jboss.xb.binding.metadata.unmarshalling.TopElementBinding;
13 import org.jboss.xb.binding.metadata.unmarshalling.ElementBinding;
14 import org.jboss.xb.binding.metadata.unmarshalling.BasicElementBinding;
15 import org.jboss.xb.binding.metadata.unmarshalling.AttributeBinding;
16 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBindingStack;
17 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinder;
18 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueBinding;
19 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueContainer;
20 import org.jboss.xb.binding.JBossXBRuntimeException;
21
22 import javax.xml.namespace.QName JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.lang.reflect.Field JavaDoc;
29 import java.lang.reflect.Method JavaDoc;
30 import java.lang.reflect.Modifier JavaDoc;
31 import java.lang.reflect.Constructor JavaDoc;
32
33 /**
34  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
35  * @version <tt>$Revision: 1.1.2.1 $</tt>
36  */

37 public class DocumentBindingFactoryImpl
38    extends DocumentBindingFactory
39 {
40    public DocumentBindingStack newDocumentBindingStack()
41    {
42       return new DocumentBindingStackImpl();
43    }
44
45    public NamespaceBinding bindNamespace(DocumentBinding doc, String JavaDoc namespaceUri, String JavaDoc javaPackage)
46    {
47       DocumentBindingStackImpl docStack = (DocumentBindingStackImpl)doc;
48       return docStack.bindNamespace(new DefaultNamespaceBinding(docStack, namespaceUri, javaPackage));
49    }
50
51    public TopElementBinding bindTopElement(NamespaceBinding ns, String JavaDoc elementName, Class JavaDoc javaClass)
52    {
53       NamespaceBindingStack nsStack = (NamespaceBindingStack)ns;
54       return nsStack.bindTopElement(new DefaultTopElementBinding(nsStack, elementName, javaClass));
55    }
56
57    public ElementBinding bindElement(BasicElementBinding parent,
58                                      String JavaDoc namespaceUri,
59                                      String JavaDoc elementName,
60                                      String JavaDoc fieldName,
61                                      Class JavaDoc javaType)
62    {
63       BasicElementBindingStack basicStack = (BasicElementBindingStack)parent;
64       return basicStack.bindChild(
65          new DefaultElementBinding(parent, new QName JavaDoc(namespaceUri, elementName), fieldName, javaType)
66       );
67    }
68
69    public XmlValueBinding bindValue(BasicElementBinding element, String JavaDoc fieldName, Class JavaDoc javaType)
70    {
71       ElementBindingStack basicStack = (ElementBindingStack)element;
72       return basicStack.bindValue(new DefaultXmlValueBinding(element, fieldName, javaType));
73    }
74
75    public XmlValueBinding bindValue(XmlValueContainer container, String JavaDoc fieldName, Class JavaDoc javaType)
76    {
77       XmlValueContainerStack stack = (XmlValueContainerStack)container;
78       return stack.bindValue(new DefaultXmlValueBinding(container, fieldName, javaType));
79    }
80
81    public AttributeBinding bindAttribute(BasicElementBinding parent,
82                                          String JavaDoc namespaceUri,
83                                          String JavaDoc attributeName,
84                                          String JavaDoc fieldName,
85                                          Class JavaDoc javaType)
86    {
87       BasicElementBindingStack stack = (BasicElementBindingStack)parent;
88       AttributeBinding attr = new AttributeBindingImpl(new QName JavaDoc(namespaceUri, attributeName),
89          javaType,
90          parent.getJavaType(),
91          fieldName
92       );
93       stack.bindAttribute(attr);
94       return attr;
95    }
96
97    public DocumentBinding newDocumentBinding()
98    {
99       return new DocumentBindingStackImpl();
100    }
101
102    //
103
// Inner
104
//
105

106    // Abstract classes for this stack implementation
107

108    public static abstract class AbstractDocumentBinding
109       implements DocumentBinding
110    {
111       protected final DocumentBinding doc;
112
113       protected AbstractDocumentBinding(DocumentBinding doc)
114       {
115          if(doc == null)
116          {
117             // todo
118
doc = DocumentBindingFactory.newInstance().newDocumentBindingStack();
119             ((DocumentBindingStackImpl)doc).push(this);
120          }
121          this.doc = doc;
122       }
123
124       public NamespaceBinding getNamespace(String JavaDoc namespaceUri)
125       {
126          return doc.getNamespace(namespaceUri);
127       }
128
129       protected abstract NamespaceBinding getNamespaceLocal(String JavaDoc namespaceUri);
130    }
131
132    public static abstract class AbstractNamespaceBinding
133       implements NamespaceBinding
134    {
135       protected final String JavaDoc namespaceUri;
136       private final DocumentBinding doc;
137
138       protected AbstractNamespaceBinding(DocumentBinding doc, String JavaDoc namespaceUri)
139       {
140          this.namespaceUri = namespaceUri;
141          this.doc = doc;
142       }
143
144       public DocumentBinding getDocument()
145       {
146          return doc;
147       }
148
149       public String JavaDoc getNamespaceUri()
150       {
151          return namespaceUri;
152       }
153
154       public String JavaDoc getJavaPackage()
155       {
156          return doc.getNamespace(namespaceUri).getJavaPackage();
157       }
158
159       public TopElementBinding getTopElement(String JavaDoc elementName)
160       {
161          return doc.getNamespace(namespaceUri).getTopElement(elementName);
162       }
163
164       protected abstract String JavaDoc getJavaPackageLocal();
165
166       protected abstract TopElementBinding getTopElementLocal(String JavaDoc elementName);
167    }
168
169    public static abstract class AbstractXmlValueContainer
170       implements XmlValueContainer
171    {
172       protected final QName JavaDoc name;
173
174       public AbstractXmlValueContainer(QName JavaDoc name)
175       {
176          this.name = name;
177       }
178
179       public QName JavaDoc getName()
180       {
181          return name;
182       }
183
184       public XmlValueBinding getValue()
185       {
186          return getValueStackReference().getValue();
187       }
188
189       public Class JavaDoc getJavaType()
190       {
191          return getValueStackReference().getJavaType();
192       }
193
194       protected abstract XmlValueContainer getValueStackReference();
195
196       protected abstract XmlValueBinding getValueLocal();
197
198       protected abstract Class JavaDoc getJavaTypeLocal();
199    }
200
201    public static abstract class AbstractBasicElementBinding
202       extends AbstractXmlValueContainer
203       implements BasicElementBinding
204    {
205       protected AbstractBasicElementBinding(QName JavaDoc elementName)
206       {
207          super(elementName);
208       }
209
210       public DocumentBinding getDocument()
211       {
212          return getStackReference().getDocument();
213       }
214
215       public ElementBinding getElement(QName JavaDoc elementName)
216       {
217          return getStackReference().getElement(elementName);
218       }
219
220       public AttributeBinding getAttribute(QName JavaDoc attributeName)
221       {
222          return getStackReference().getAttribute(attributeName);
223       }
224
225       public XmlValueBinding getValue()
226       {
227          return getStackReference().getValue();
228       }
229
230       protected XmlValueContainer getValueStackReference()
231       {
232          return getStackReference();
233       }
234
235       protected abstract Class JavaDoc getJavaTypeLocal();
236
237       protected abstract ElementBinding getElementLocal(QName JavaDoc elementName);
238
239       protected abstract AttributeBinding getAttributeLocal(QName JavaDoc attributeName);
240
241       protected abstract XmlValueBinding getValueLocal();
242
243       protected abstract BasicElementBinding getStackReference();
244    }
245
246    public static abstract class AbstractTopElementBinding
247       extends AbstractBasicElementBinding
248       implements TopElementBinding
249    {
250       protected final NamespaceBinding ns;
251
252       protected AbstractTopElementBinding(NamespaceBinding ns, String JavaDoc elementName)
253       {
254          super(new QName JavaDoc(ns.getNamespaceUri(), elementName));
255          this.ns = ns;
256       }
257
258       protected BasicElementBinding getStackReference()
259       {
260          return ns.getTopElement(name.getLocalPart());
261       }
262    }
263
264    public static abstract class AbstractElementBinding
265       extends AbstractBasicElementBinding
266       implements ElementBinding
267    {
268       protected final BasicElementBinding parent;
269
270       protected AbstractElementBinding(BasicElementBinding parent, QName JavaDoc elementName)
271       {
272          super(elementName);
273          this.parent = parent;
274       }
275
276       public Field JavaDoc getField()
277       {
278          return ((ElementBinding)getStackReference()).getField();
279       }
280
281       public Method JavaDoc getGetter()
282       {
283          return ((ElementBinding)getStackReference()).getGetter();
284       }
285
286       public Method JavaDoc getSetter()
287       {
288          return ((ElementBinding)getStackReference()).getSetter();
289       }
290
291       public Class JavaDoc getFieldType()
292       {
293          return ((ElementBinding)getStackReference()).getFieldType();
294       }
295
296       protected BasicElementBinding getStackReference()
297       {
298          return parent.getElement(name);
299       }
300
301       protected abstract Field JavaDoc getFieldLocal();
302
303       protected abstract Method JavaDoc getGetterLocal();
304
305       protected abstract Method JavaDoc getSetterLocal();
306
307       protected abstract Class JavaDoc getFieldTypeLocal();
308    }
309
310    public static abstract class AbstractXmlValueBinding
311       extends AbstractXmlValueContainer
312       implements XmlValueBinding
313    {
314       private final XmlValueContainer container;
315
316       protected AbstractXmlValueBinding(XmlValueContainer container)
317       {
318          super(container.getName());
319          this.container = container;
320       }
321
322       public Field JavaDoc getField()
323       {
324          return container.getValue().getField();
325       }
326
327       public Method JavaDoc getGetter()
328       {
329          return container.getValue().getGetter();
330       }
331
332       public Method JavaDoc getSetter()
333       {
334          return container.getValue().getSetter();
335       }
336
337       public Class JavaDoc getFieldType()
338       {
339          return container.getValue().getFieldType();
340       }
341
342       public XmlValueBinding getValue()
343       {
344          return container.getValue().getValue();
345       }
346
347       protected XmlValueContainer getValueStackReference()
348       {
349          return container.getValue();
350       }
351
352       protected abstract Field JavaDoc getFieldLocal();
353
354       protected abstract Method JavaDoc getGetterLocal();
355
356       protected abstract Method JavaDoc getSetterLocal();
357
358       protected abstract Class JavaDoc getFieldTypeLocal();
359    }
360
361    // Default impl used internally
362

363    private static class DefaultNamespaceBinding
364       extends AbstractNamespaceBinding
365    {
366       private final String JavaDoc javaPackage;
367
368       public DefaultNamespaceBinding(DocumentBinding doc, String JavaDoc namespaceUri, String JavaDoc javaPackage)
369       {
370          super(doc, namespaceUri);
371          this.javaPackage = javaPackage;
372       }
373
374       protected String JavaDoc getJavaPackageLocal()
375       {
376          return javaPackage;
377       }
378
379       protected TopElementBinding getTopElementLocal(String JavaDoc elementName)
380       {
381          return null;
382       }
383    }
384
385    private static class DefaultTopElementBinding
386       extends AbstractTopElementBinding
387    {
388       private final Class JavaDoc javaType;
389
390       DefaultTopElementBinding(NamespaceBinding ns, String JavaDoc elementName, Class JavaDoc javaType)
391       {
392          super(ns, elementName);
393          this.javaType = javaType;
394       }
395
396       protected Class JavaDoc getJavaTypeLocal()
397       {
398          return javaType;
399       }
400
401       protected ElementBinding getElementLocal(QName JavaDoc elementName)
402       {
403          return null;
404       }
405
406       protected AttributeBinding getAttributeLocal(QName JavaDoc attributeName)
407       {
408          return null;
409       }
410
411       protected XmlValueBinding getValueLocal()
412       {
413          return null;
414       }
415    }
416
417    private static class DefaultElementBinding
418       extends AbstractElementBinding
419    {
420       private final Field JavaDoc field;
421       private final Method JavaDoc getter;
422       private final Method JavaDoc setter;
423       private final Class JavaDoc fieldType;
424       private final Class JavaDoc javaType;
425
426       public DefaultElementBinding(BasicElementBinding parent, QName JavaDoc elementName, String JavaDoc fieldName, Class JavaDoc javaType)
427       {
428          super(parent, elementName);
429
430          Class JavaDoc parentType = parent.getJavaType();
431          if(Collection JavaDoc.class.isAssignableFrom(parentType))
432          {
433             field = null;
434             getter = null;
435             setter = null;
436             fieldType = null;
437          }
438          else
439          {
440             Field JavaDoc tmpField = null;
441             Method JavaDoc tmpGetter = null;
442             Method JavaDoc tmpSetter = null;
443             Class JavaDoc tmpFieldType;
444             try
445             {
446                tmpField = parentType.getField(fieldName);
447                tmpFieldType = tmpField.getType();
448             }
449             catch(NoSuchFieldException JavaDoc e)
450             {
451                String JavaDoc baseMethodName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
452                try
453                {
454                   tmpGetter = parentType.getMethod("get" + baseMethodName, null);
455                   tmpFieldType = tmpGetter.getReturnType();
456                   try
457                   {
458                      tmpSetter = parentType.getMethod("set" + baseMethodName, new Class JavaDoc[]{tmpGetter.getReturnType()});
459                   }
460                   catch(NoSuchMethodException JavaDoc nosetter)
461                   {
462                      // this one is immutable
463
}
464                }
465                catch(NoSuchMethodException JavaDoc e1)
466                {
467                   throw new JBossXBRuntimeException("Failed to bind " +
468                      elementName +
469                      " to field " +
470                      fieldName +
471                      " in " +
472                      parentType +
473                      ": neither field nor getter/setter were found."
474                   );
475                }
476             }
477
478             field = tmpField;
479             getter = tmpGetter;
480             setter = tmpSetter;
481             fieldType = tmpFieldType;
482          }
483
484          if(fieldType == null)
485          {
486             this.javaType = javaType == null ? String JavaDoc.class : javaType;
487          }
488          else
489          {
490             if(javaType == null)
491             {
492                this.javaType = fieldType;
493             }
494             else if(Collection JavaDoc.class == fieldType ||
495                Collection JavaDoc.class.isAssignableFrom(fieldType) ||
496                fieldType.isAssignableFrom(javaType))
497             {
498                this.javaType = javaType;
499             }
500             else
501             {
502                throw new JBossXBRuntimeException("Failed to bind " +
503                   elementName +
504                   " to field " +
505                   fieldName +
506                   " in " +
507                   parentType +
508                   ": field type " + fieldType + " is not assignable from the specified Java type " + javaType
509                );
510             }
511
512             if(this.javaType.isInterface() || Modifier.isAbstract(this.javaType.getModifiers()))
513             {
514                throw new JBossXBRuntimeException("Failed to bind " +
515                   elementName +
516                   " to field " +
517                   fieldName +
518                   " in " +
519                   parentType +
520                   ": Java type is abstract class or interface."
521                );
522             }
523          }
524       }
525
526       protected Field JavaDoc getFieldLocal()
527       {
528          return field;
529       }
530
531       protected Method JavaDoc getGetterLocal()
532       {
533          return getter;
534       }
535
536       protected Method JavaDoc getSetterLocal()
537       {
538          return setter;
539       }
540
541       protected Class JavaDoc getFieldTypeLocal()
542       {
543          return fieldType;
544       }
545
546       protected Class JavaDoc getJavaTypeLocal()
547       {
548          return javaType;
549       }
550
551       protected ElementBinding getElementLocal(QName JavaDoc elementName)
552       {
553          return null;
554       }
555
556       protected AttributeBinding getAttributeLocal(QName JavaDoc attributeName)
557       {
558          return null;
559       }
560
561       protected XmlValueBinding getValueLocal()
562       {
563          return null;
564       }
565    }
566
567    private static class DefaultXmlValueBinding
568       extends AbstractXmlValueBinding
569    {
570       private final Field JavaDoc field;
571       private final Method JavaDoc getter;
572       private final Method JavaDoc setter;
573       private final Class JavaDoc fieldType;
574       private final Class JavaDoc javaType;
575
576       public DefaultXmlValueBinding(XmlValueContainer container, String JavaDoc fieldName, Class JavaDoc javaType)
577       {
578          super(container);
579
580          Class JavaDoc parentType = container.getJavaType();
581          if(Collection JavaDoc.class.isAssignableFrom(parentType))
582          {
583             field = null;
584             getter = null;
585             setter = null;
586             fieldType = null;
587          }
588          else
589          {
590             Field JavaDoc tmpField = null;
591             Method JavaDoc tmpGetter = null;
592             Method JavaDoc tmpSetter = null;
593             Class JavaDoc tmpFieldType = null;
594             try
595             {
596                tmpField = parentType.getField(fieldName);
597                tmpFieldType = tmpField.getType();
598             }
599             catch(NoSuchFieldException JavaDoc e)
600             {
601                String JavaDoc baseMethodName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
602                try
603                {
604                   tmpGetter = parentType.getMethod("get" + baseMethodName, null);
605                   tmpFieldType = tmpGetter.getReturnType();
606                   try
607                   {
608                      tmpSetter = parentType.getMethod("set" + baseMethodName, new Class JavaDoc[]{tmpGetter.getReturnType()});
609                   }
610                   catch(NoSuchMethodException JavaDoc nosetter)
611                   {
612                      // this one is immutable
613
}
614                }
615                catch(NoSuchMethodException JavaDoc e1)
616                {
617                   throw new JBossXBRuntimeException("Failed to bind value of " +
618                      container.getName() +
619                      " to field " +
620                      fieldName +
621                      " in " +
622                      parentType +
623                      ": neither field nor getter/setter were found."
624                   );
625                }
626             }
627
628             field = tmpField;
629             getter = tmpGetter;
630             setter = tmpSetter;
631             fieldType = tmpFieldType;
632          }
633
634          if(fieldType == null)
635          {
636             this.javaType = javaType == null ? String JavaDoc.class : javaType;
637          }
638          else
639          {
640             if(javaType == null)
641             {
642                this.javaType = fieldType;
643             }
644             else if(Collection JavaDoc.class == fieldType ||
645                Collection JavaDoc.class.isAssignableFrom(fieldType) ||
646                fieldType.isAssignableFrom(javaType))
647             {
648                this.javaType = javaType;
649             }
650             else
651             {
652                throw new JBossXBRuntimeException("Failed to bind value of " +
653                   container.getName() +
654                   " to field " +
655                   fieldName +
656                   " in " +
657                   parentType +
658                   ": field type " + fieldType + " is not assignable from the specified Java type " + javaType
659                );
660             }
661
662             if(this.javaType.isInterface() || Modifier.isAbstract(this.javaType.getModifiers()))
663             {
664                throw new JBossXBRuntimeException("Failed to bind value of " +
665                   container.getName() +
666                   " to field " +
667                   fieldName +
668                   " in " +
669                   parentType +
670                   ": Java type is abstract class or interface."
671                );
672             }
673          }
674       }
675
676       protected Field JavaDoc getFieldLocal()
677       {
678          return field;
679       }
680
681       protected Method JavaDoc getGetterLocal()
682       {
683          return getter;
684       }
685
686       protected Method JavaDoc getSetterLocal()
687       {
688          return setter;
689       }
690
691       protected Class JavaDoc getFieldTypeLocal()
692       {
693          return fieldType;
694       }
695
696       protected XmlValueBinding getValueLocal()
697       {
698          return null;
699       }
700
701       protected Class JavaDoc getJavaTypeLocal()
702       {
703          return javaType;
704       }
705    }
706
707    // Stack impl
708

709    class DocumentBindingStackImpl
710       implements DocumentBindingStack
711    {
712       private final List JavaDoc stack = new ArrayList JavaDoc();
713       private final Map JavaDoc namespaces = new HashMap JavaDoc();
714
715       public DocumentBindingStackImpl()
716       {
717       }
718
719       public DocumentBindingStackImpl(DocumentBinding doc)
720       {
721          if(doc != null)
722          {
723             push(doc);
724          }
725       }
726
727       void push(DocumentBinding doc)
728       {
729          stack.add(doc);
730       }
731
732       NamespaceBindingStack bindNamespace(NamespaceBinding ns)
733       {
734          NamespaceBindingStack stack = (NamespaceBindingStack)getNamespace(ns.getNamespaceUri());
735          if(stack == null)
736          {
737             stack = new NamespaceBindingStack(this, ns.getNamespaceUri());
738             namespaces.put(ns.getNamespaceUri(), stack);
739