KickJava   Java API By Example, From Geeks To Geeks.

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


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.Util;
10 import org.jboss.xb.binding.JBossXBRuntimeException;
11 import org.jboss.xb.binding.SimpleTypeBindings;
12 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinding;
13 import org.jboss.xb.binding.metadata.unmarshalling.NamespaceBinding;
14 import org.jboss.xb.binding.metadata.unmarshalling.TopElementBinding;
15 import org.jboss.xb.binding.metadata.unmarshalling.BasicElementBinding;
16 import org.jboss.xb.binding.metadata.unmarshalling.ElementBinding;
17 import org.jboss.xb.binding.metadata.unmarshalling.AttributeBinding;
18 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueBinding;
19 import org.jboss.logging.Logger;
20 import org.apache.xerces.xs.XSImplementation;
21 import org.apache.xerces.xs.XSModel;
22 import org.apache.xerces.xs.XSLoader;
23 import org.apache.xerces.xs.StringList;
24 import org.apache.xerces.xs.XSNamedMap;
25 import org.apache.xerces.xs.XSConstants;
26 import org.apache.xerces.xs.XSElementDeclaration;
27 import org.apache.xerces.xs.XSTypeDefinition;
28 import org.apache.xerces.xs.XSComplexTypeDefinition;
29 import org.apache.xerces.xs.XSParticle;
30 import org.apache.xerces.xs.XSTerm;
31 import org.apache.xerces.xs.XSModelGroup;
32 import org.apache.xerces.xs.XSObjectList;
33 import org.apache.xerces.dom3.bootstrap.DOMImplementationRegistry;
34
35 import javax.xml.namespace.QName JavaDoc;
36 import java.util.Collection JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.lang.reflect.Method JavaDoc;
40 import java.lang.reflect.Field JavaDoc;
41 import java.lang.reflect.Modifier JavaDoc;
42
43 /**
44  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
45  * @version <tt>$Revision: 1.1.2.1 $</tt>
46  */

47 public class XsdBinder
48 {
49    private static final Logger log = Logger.getLogger(XsdBinder.class);
50
51    private XsdBinder()
52    {
53    }
54
55    public static DocumentBinding bindXsd(String JavaDoc xsdUrl)
56    {
57       return bindXsd(xsdUrl, null);
58    }
59
60    public static DocumentBinding bindXsd(String JavaDoc xsdUrl, DocumentBinding delegate)
61    {
62       DocumentBindingImpl localDoc;
63       if(delegate instanceof DocumentBindingImpl)
64       {
65          localDoc = (DocumentBindingImpl)delegate;
66       }
67       else
68       {
69          localDoc = new DocumentBindingImpl(delegate);
70       }
71
72       XSModel model = loadSchema(xsdUrl);
73       StringList namespaces = model.getNamespaces();
74       for(int i = 0; i < namespaces.getLength(); ++i)
75       {
76          String JavaDoc namespaceUri = namespaces.item(i);
77          NamespaceBindingImpl ns = localDoc.bindNamespace(namespaceUri);
78
79          XSNamedMap components = model.getComponentsByNamespace(XSConstants.ELEMENT_DECLARATION, namespaceUri);
80          for(int j = 0; j < components.getLength(); ++j)
81          {
82             XSElementDeclaration element = (XSElementDeclaration)components.item(j);
83             bindTopElement(localDoc, ns, element);
84          }
85       }
86
87       return localDoc;
88    }
89
90    private static final void bindTopElement(DocumentBinding doc,
91                                             NamespaceBindingImpl ns,
92                                             XSElementDeclaration element)
93    {
94       TopElementBindingImpl top = new TopElementBindingImpl(ns, element);
95       ns.addTopElement(top);
96
97       bindComplexElement(element, doc, top);
98    }
99
100    private static void bindComplexElement(XSElementDeclaration elementDecl,
101                                           DocumentBinding doc,
102                                           ParentElement parentBinding)
103    {
104       XSTypeDefinition type = elementDecl.getTypeDefinition();
105       if(type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
106       {
107          XSComplexTypeDefinition complexType = (XSComplexTypeDefinition)type;
108          XSParticle particle = complexType.getParticle();
109          if(particle != null)
110          {
111             bindParticle(doc, parentBinding, particle);
112          }
113
114          /* todo attributes
115          XSObjectList attributeUses = complexType.getAttributeUses();
116          for(int i = 0; i < attributeUses.getLength(); ++i)
117          {
118             XSAttributeUse attrUse = (XSAttributeUse)attributeUses.item(i);
119             XSAttributeDeclaration attrDec = attrUse.getAttrDeclaration();
120
121             String baseFieldName = Util.xmlNameToClassName(elementDecl.getName(), true);
122             String fieldName = Character.toLowerCase(baseFieldName.charAt(0)) + baseFieldName.substring(1);
123
124             NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
125             String fqClsName = ns.getJavaPackage() +
126                "." +
127                Util.xmlNameToClassName(getBaseForClassName(elementDecl), true);
128
129             Class javaType;
130             try
131             {
132                javaType = Thread.currentThread().getContextClassLoader().loadClass(fqClsName);
133             }
134             catch(ClassNotFoundException e)
135             {
136                javaType = null;
137             }
138
139             factory.bindAttribute(parentBinding, attrDec.getNamespace(), attrDec.getName(), fieldName, javaType);
140          }
141          */

142       }
143    }
144
145    private static void bindParticle(DocumentBinding doc,
146                                     ParentElement parent,
147                                     XSParticle particle)
148    {
149       XSTerm term = particle.getTerm();
150       switch(term.getType())
151       {
152          case XSConstants.MODEL_GROUP:
153             bindModelGroup(doc, parent, (XSModelGroup)term);
154             break;
155          case XSConstants.WILDCARD:
156             // todo bindWildcard((XSWildcard)term);
157
break;
158          case XSConstants.ELEMENT_DECLARATION:
159             bindElement(doc, parent, (XSElementDeclaration)term);
160             break;
161          default:
162             throw new IllegalStateException JavaDoc("Unexpected term type: " + term.getType());
163       }
164    }
165
166    private static void bindElement(DocumentBinding doc,
167                                    ParentElement parent,
168                                    XSElementDeclaration elementDecl)
169    {
170       ElementBindingImpl child = new ElementBindingImpl(parent, elementDecl);
171       parent.addChild(child);
172       bindComplexElement(elementDecl, doc, child);
173    }
174
175    private static void bindModelGroup(DocumentBinding doc,
176                                       ParentElement parent,
177                                       XSModelGroup modelGroup)
178    {
179       XSObjectList particles = modelGroup.getParticles();
180       for(int i = 0; i < particles.getLength(); ++i)
181       {
182          XSParticle particle = (XSParticle)particles.item(i);
183          bindParticle(doc, parent, particle);
184       }
185    }
186
187    // Private
188

189    private static XSModel loadSchema(String JavaDoc xsdURL)
190    {
191       XSImplementation impl = getXSImplementation();
192       XSLoader schemaLoader = impl.createXSLoader(null);
193       XSModel model = schemaLoader.loadURI(xsdURL);
194       if(model == null)
195       {
196          throw new IllegalArgumentException JavaDoc("Invalid URI for schema: " + xsdURL);
197       }
198
199       return model;
200    }
201
202    private static XSImplementation getXSImplementation()
203    {
204       // Get DOM Implementation using DOM Registry
205
System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMXSImplementationSourceImpl");
206
207       XSImplementation impl;
208       try
209       {
210          DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
211          impl = (XSImplementation)registry.getDOMImplementation("XS-Loader");
212       }
213       catch(Exception JavaDoc e)
214       {
215          log.error("Failed to create schema loader.", e);
216          throw new IllegalStateException JavaDoc("Failed to create schema loader: " + e.getMessage());
217       }
218       return impl;
219    }
220
221    // Private
222

223    public static final class DocumentBindingImpl
224       extends DocumentBindingFactoryImpl.AbstractDocumentBinding
225    {
226       private final Map namespaces = new HashMap JavaDoc();
227
228       public DocumentBindingImpl(DocumentBinding doc)
229       {
230          super(doc);
231       }
232
233       NamespaceBindingImpl bindNamespace(String JavaDoc namespaceUri)
234       {
235          NamespaceBindingImpl ns = new NamespaceBindingImpl(doc, namespaceUri);
236          namespaces.put(namespaceUri, ns);
237          return ns;
238       }
239
240       protected NamespaceBinding getNamespaceLocal(String JavaDoc namespaceUri)
241       {
242          return (NamespaceBinding)namespaces.get(namespaceUri);
243       }
244    }
245
246    private static final class NamespaceBindingImpl
247       extends DocumentBindingFactoryImpl.AbstractNamespaceBinding
248    {
249       private final Map tops = new HashMap JavaDoc();
250
251       public NamespaceBindingImpl(DocumentBinding doc, String JavaDoc namespaceUri)
252       {
253          super(doc, namespaceUri);
254       }
255
256       protected String JavaDoc getJavaPackageLocal()
257       {
258          return Util.xmlNamespaceToJavaPackage(namespaceUri);
259       }
260
261       protected TopElementBinding getTopElementLocal(String JavaDoc elementName)
262       {
263          return (TopElementBinding)tops.get(elementName);
264       }
265
266       void addTopElement(TopElementBindingImpl top)
267       {
268          tops.put(top.getName().getLocalPart(), top);
269       }
270    }
271
272    private static final class ElementBindingImpl
273       extends DocumentBindingFactoryImpl.AbstractElementBinding
274       implements ParentElement
275    {
276       private final XSElementDeclaration elementDecl;
277       private final Map children = new HashMap JavaDoc();
278       private Class JavaDoc javaType;
279       private Class JavaDoc fieldType;
280       private Method JavaDoc getter;
281       private Method JavaDoc setter;
282       private Field JavaDoc field;
283
284       public ElementBindingImpl(BasicElementBinding parent, XSElementDeclaration elementDecl)
285       {
286          super(parent, new QName JavaDoc(elementDecl.getNamespace(), elementDecl.getName()));
287          this.elementDecl = elementDecl;
288       }
289
290       private void init()
291       {
292          DocumentBinding doc = parent.getDocument();
293
294          // first try to use XSD type
295
XSTypeDefinition typeDef = elementDecl.getTypeDefinition();
296          String JavaDoc typeBasedClsName = null;
297          if("http://www.w3.org/2001/XMLSchema".equals(typeDef.getNamespace()))
298          {
299             javaType = SimpleTypeBindings.classForType(typeDef.getName());
300          }
301          else if(typeDef.getName() != null)
302          {
303             NamespaceBinding ns = doc.getNamespace(typeDef.getNamespace());
304             typeBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(typeDef.getName(), true);
305             try
306             {
307                javaType = Thread.currentThread().getContextClassLoader().loadClass(typeBasedClsName);
308             }
309             catch(ClassNotFoundException JavaDoc e)
310             {
311             }
312          }
313
314          String JavaDoc elBasedClsName = Util.xmlNameToClassName(elementDecl.getName(), true);
315          if(javaType == null)
316          {
317             NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
318             // using type didn't help, let's try element's name
319
// note: here we use element's namespace, not type's one
320
try
321             {
322                javaType =
323                   Thread.currentThread().getContextClassLoader().loadClass(ns.getJavaPackage() + "." + elBasedClsName);
324             }
325             catch(ClassNotFoundException JavaDoc e1)
326             {
327                // this also didn't work
328
}
329          }
330
331          Class JavaDoc parentType = parent.getJavaType();
332          if(Collection JavaDoc.class.isAssignableFrom(parentType))
333          {
334             if(javaType == null)
335             {
336                javaType = String JavaDoc.class;
337             }
338          }
339          else
340          {
341             try
342             {
343                getter = parentType.getMethod("get" + elBasedClsName, null);
344                fieldType = getter.getReturnType();
345                try
346                {
347                   setter = parentType.getMethod("set" + elBasedClsName, new Class JavaDoc[]{getter.getReturnType()});
348                }
349                catch(NoSuchMethodException JavaDoc e)
350                {
351                   // todo immutable!!!
352
setter = null;
353                }
354             }
355             catch(NoSuchMethodException JavaDoc e)
356             {
357                String JavaDoc fieldName = Util.xmlNameToFieldName(elementDecl.getName(), true);
358                try
359                {
360                   field = parentType.getField(fieldName);
361                   fieldType = field.getType();
362                }
363                catch(NoSuchFieldException JavaDoc e1)
364                {
365                }
366             }
367
368             if(fieldType != null)
369             {
370                if(Modifier.isFinal(fieldType.getModifiers()) ||
371                   javaType == null &&
372                   !Modifier.isInterface(fieldType.getModifiers()) &&
373                   !Modifier.isAbstract(fieldType.getModifiers()))
374                {
375                   javaType = fieldType;
376                }
377                else if(fieldType == Collection JavaDoc.class || Collection JavaDoc.class.isAssignableFrom(fieldType))
378                {
379                   if(javaType == null)
380                   {
381                      // todo: other collection types
382
javaType = java.util.ArrayList JavaDoc.class;
383                   }
384                }
385                else if(javaType != null)
386                {
387                   if(javaType != fieldType && !fieldType.isAssignableFrom(javaType))
388                   {
389                      javaType = null;
390                   }
391                }
392             }
393          }
394
395          if(javaType == null)
396          {
397             throw new JBossXBRuntimeException("Failed to bind element " +
398                name +
399                " to any non-abstract Java type. Parent is " +
400                parentType +
401                ", field is " +
402                fieldType
403                + ", base=" + elBasedClsName
404             );
405          }
406       }
407
408       protected Field JavaDoc getFieldLocal()
409       {
410          if(javaType == null)
411          {
412             init();
413          }
414          return field;
415       }
416
417       protected Method JavaDoc getGetterLocal()
418       {
419          if(javaType == null)
420          {
421             init();
422          }
423          return getter;
424       }
425
426       protected Method JavaDoc getSetterLocal()
427       {
428          if(javaType == null)
429          {
430             init();
431          }
432          return setter;
433       }
434
435       protected Class JavaDoc getFieldTypeLocal()
436       {
437          if(javaType == null)
438          {
439             init();
440          }
441          return fieldType;
442       }
443
444       protected Class JavaDoc getJavaTypeLocal()
445       {
446          if(javaType == null)
447          {
448             init();
449          }
450          return javaType;
451       }
452
453       protected ElementBinding getElementLocal(QName JavaDoc elementName)
454       {
455          return (ElementBinding)children.get(elementName);
456       }
457
458       protected AttributeBinding getAttributeLocal(QName JavaDoc attributeName)
459       {
460          String JavaDoc fieldName = Util.xmlNameToClassName(attributeName.getLocalPart(), true);
461          fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1);
462          return new AttributeBindingImpl(attributeName, null, getJavaType(), fieldName);
463       }
464
465       protected XmlValueBinding getValueLocal()
466       {
467          // todo: implement getValueLocal
468
throw new UnsupportedOperationException JavaDoc("getValueLocal is not implemented.");
469       }
470
471       public void addChild(BasicElementBinding child)
472       {
473          children.put(child.getName(), child);
474       }
475    }
476
477    private static class TopElementBindingImpl
478       extends DocumentBindingFactoryImpl.AbstractTopElementBinding
479       implements ParentElement
480    {
481       private final XSElementDeclaration elementDecl;
482       private final Map children = new HashMap JavaDoc();
483       protected Class JavaDoc javaType;
484
485       public TopElementBindingImpl(NamespaceBinding ns, XSElementDeclaration elementDecl)
486       {
487          super(ns, elementDecl.getName());
488          this.elementDecl = elementDecl;
489       }
490
491       private void init()
492       {
493          DocumentBinding doc = ns.getDocument();
494
495          // first try to use XSD type
496
XSTypeDefinition typeDef = elementDecl.getTypeDefinition();
497          String JavaDoc typeBasedClsName = null;
498          if("http://www.w3.org/2001/XMLSchema".equals(typeDef.getNamespace()))
499          {
500             javaType = SimpleTypeBindings.classForType(typeDef.getName());
501          }
502          else if(typeDef.getName() != null)
503          {
504             NamespaceBinding ns = doc.getNamespace(typeDef.getNamespace());
505             typeBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(typeDef.getName(), true);
506             try
507             {
508                javaType = Thread.currentThread().getContextClassLoader().loadClass(typeBasedClsName);
509             }
510             catch(ClassNotFoundException JavaDoc e)
511             {
512             }
513          }
514
515          if(javaType == null)
516          {
517             // using type didn't help, let's try element's name
518
// note: here we use element's namespace, not type's one
519
NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
520             String JavaDoc elBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(elementDecl.getName(), true);
521             try
522             {
523                javaType = Thread.currentThread().getContextClassLoader().loadClass(elBasedClsName);
524             }
525             catch(ClassNotFoundException JavaDoc e1)
526             {
527                throw new JBossXBRuntimeException("Failed to bind element " +
528                   name +
529                   " using XSD type (" +
530                   typeBasedClsName +
531                   ") and element name (" +
532                   elBasedClsName +
533                   "): classes not found."
534                );
535             }
536          }
537       }
538
539       protected Class JavaDoc getJavaTypeLocal()
540       {
541          if(javaType == null)
542          {
543             init();
544          }
545          return javaType;
546       }
547
548       protected ElementBinding getElementLocal(QName JavaDoc elementName)
549       {
550          return (ElementBinding)children.get(elementName);
551       }
552
553       protected AttributeBinding getAttributeLocal(QName JavaDoc attributeName)
554       {
555          String JavaDoc fieldName = Util.xmlNameToClassName(attributeName.getLocalPart(), true);
556          fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1);
557          return new AttributeBindingImpl(attributeName, null, getJavaType(), fieldName);
558       }
559
560       protected XmlValueBinding getValueLocal()
561       {
562          // todo: implement getValueLocal
563
throw new UnsupportedOperationException JavaDoc("getValueLocal is not implemented.");
564       }
565
566       public void addChild(BasicElementBinding child)
567       {
568          children.put(child.getName(), child);
569       }
570    }
571
572    interface ParentElement
573       extends BasicElementBinding
574    {
575       void addChild(BasicElementBinding child);
576    }
577 }
578
Popular Tags