KickJava   Java API By Example, From Geeks To Geeks.

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


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.xml.sax.SAXException JavaDoc;
10 import org.xml.sax.InputSource JavaDoc;
11 import org.xml.sax.Attributes JavaDoc;
12 import org.apache.ws.jaxme.xs.XSParser;
13 import org.apache.ws.jaxme.xs.XSSchema;
14 import org.apache.ws.jaxme.xs.XSElement;
15 import org.apache.ws.jaxme.xs.XSType;
16 import org.apache.ws.jaxme.xs.XSSimpleType;
17 import org.apache.ws.jaxme.xs.XSComplexType;
18 import org.apache.ws.jaxme.xs.XSParticle;
19 import org.apache.ws.jaxme.xs.XSGroup;
20 import org.apache.ws.jaxme.xs.XSAttributable;
21 import org.apache.ws.jaxme.xs.XSAttribute;
22 import org.apache.ws.jaxme.xs.xml.XsQName;
23 import org.jboss.logging.Logger;
24
25 import javax.xml.parsers.ParserConfigurationException JavaDoc;
26 import javax.xml.namespace.QName JavaDoc;
27 import java.io.Reader JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Arrays JavaDoc;
36
37
38 /**
39  * An XML schema based org.jboss.xml.binding.Marshaller implementation.
40  *
41  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
42  * @version <tt>$Revision: 1.8.2.7 $</tt>
43  */

44 public class XsMarshaller
45    extends AbstractMarshaller
46 {
47    private static final Logger log = Logger.getLogger(XsMarshaller.class);
48
49    private Stack stack = new StackImpl();
50
51    /**
52     * ObjectModelProvider for this marshaller
53     */

54    private GenericObjectModelProvider provider;
55    /**
56     * Content the result is written to
57     */

58    private Content content = new Content();
59    /**
60     * Declared namespaces
61     */

62    private final Map JavaDoc uriByNsName = new HashMap JavaDoc();
63
64    private Object JavaDoc root;
65
66    public void marshal(Reader JavaDoc schema, ObjectModelProvider provider, Object JavaDoc root, Writer JavaDoc writer)
67       throws IOException JavaDoc, SAXException JavaDoc, ParserConfigurationException JavaDoc
68    {
69       InputSource JavaDoc source = new InputSource JavaDoc(schema);
70
71       XSParser xsParser = new XSParser();
72       xsParser.setValidating(false);
73       XSSchema xsSchema = xsParser.parse(source);
74
75       this.provider = provider instanceof GenericObjectModelProvider ?
76          (GenericObjectModelProvider)provider : new DelegatingObjectModelProvider(provider);
77
78       this.root = root;
79
80       //stack.push(document);
81
content.startDocument();
82
83       if(rootQNames.isEmpty())
84       {
85          XSElement[] elements = xsSchema.getElements();
86          for(int i = 0; i < elements.length; ++i)
87          {
88             log.info("marshalling " + elements[i].getName().getLocalName());
89             //processElement(elements[i], addedAttributes, 1);
90
processElement(elements[i], null, 1);
91          }
92       }
93       else
94       {
95          for(int i = 0; i < rootQNames.size(); ++i)
96          {
97             QName qName = (QName)rootQNames.get(i);
98             XsQName rootName = new XsQName(qName.getNamespaceURI(), qName.getLocalPart(), qName.getPrefix());
99
100             final XSElement xsRoot = xsSchema.getElement(rootName);
101             if(xsRoot == null)
102             {
103                throw new IllegalStateException JavaDoc("Root element not found: " + rootName);
104             }
105
106             //processElement(xsRoot, addedAttributes, 1);
107
processElement(xsRoot, null, 1);
108          }
109       }
110
111       content.endDocument();
112
113       // version & encoding
114
writeXmlVersion(writer);
115
116       ContentWriter contentWriter = new ContentWriter(writer, propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION));
117       content.handleContent(contentWriter);
118    }
119
120    /**
121     * Defines a namespace. The namespace declaration will appear in the root element.
122     * <p>If <code>name</code> argument is <code>null</code> or is an empty string then
123     * the passed in URI will be used for the default namespace, i.e. <code>xmlns</code>.
124     * Otherwise, the declaration will follow the format <code>xmlns:name=uri</code>.
125     * <p>If the namespace with the given name was already declared, its value is overwritten.
126     *
127     * @param name the name of the namespace to declare (can be null or empty string)
128     * @param uri the URI of the namespace.
129     */

130    public void declareNamespace(String JavaDoc name, String JavaDoc uri)
131    {
132       boolean nonEmptyName = (name != null && name.length() > 0);
133       String JavaDoc localName = (nonEmptyName ? name : "xmlns");
134       uriByNsName.put(localName, uri);
135    }
136
137    /**
138     * Adds an attribute to the top most elements.
139     * First, we check whether there is a namespace associated with the passed in prefix.
140     * If the prefix was not declared, an exception is thrown.
141     *
142     * @param prefix the prefix of the attribute to be declared
143     * @param localName local name of the attribute
144     * @param type the type of the attribute
145     * @param value the value of the attribute
146     */

147    public void addAttribute(String JavaDoc prefix, String JavaDoc localName, String JavaDoc type, String JavaDoc value)
148    {
149       final String JavaDoc uri;
150       if(prefix != null && prefix.length() > 0)
151       {
152          uri = (String JavaDoc)uriByNsName.get(prefix);
153          if(uri == null)
154          {
155             throw new IllegalStateException JavaDoc("Namespace prefix " + prefix + " is not declared. Use declareNamespace().");
156          }
157       }
158       else
159       {
160          uri = null;
161       }
162    }
163
164    /**
165     * Adds an attribute to the top most elements declaring namespace prefix if it is not yet declared.
166     *
167     * @param namespaceUri attribute's namespace URI
168     * @param prefix attribute's prefix
169     * @param localName attribute's local name
170     * @param type attribute's type
171     * @param value attribute's value
172     */

173    public void addAttribute(String JavaDoc namespaceUri, String JavaDoc prefix, String JavaDoc localName, String JavaDoc type, String JavaDoc value)
174    {
175       declareNamespace(prefix, namespaceUri);
176       addAttribute(prefix, localName, type, value);
177    }
178
179    // Private
180

181    private final void processElement(XSElement element, AttributesImpl attrs, int maxOccurs) throws SAXException JavaDoc
182    {
183       XSType type = element.getType();
184       processType(element, type, attrs, maxOccurs);
185    }
186
187    private final void processType(XSElement element, XSType type, AttributesImpl attrs, int maxOccurs)
188       throws SAXException JavaDoc
189    {
190       if(type.isSimple())
191       {
192          XSSimpleType simpleType = type.getSimpleType();
193          processSimpleType(element, simpleType, null);
194       }
195       else
196       {
197          XSComplexType complexType = type.getComplexType();
198          processComplexType(element, complexType, attrs, maxOccurs);
199       }
200    }
201
202    /**
203     * todo this should be rewritten
204     *
205     * @param element
206     * @param type
207     * @param attrs
208     */

209    private final void processSimpleType(XSElement element, XSSimpleType type, Attributes JavaDoc attrs)
210    {
211       if(type.isAtomic())
212       {
213          if(log.isTraceEnabled())
214          {
215             log.trace("atomic simple type");
216          }
217       }
218       else if(type.isList())
219       {
220          if(log.isTraceEnabled())
221          {
222             log.trace("list of types");
223          }
224       }
225       else if(type.isRestriction())
226       {
227          if(log.isTraceEnabled())
228          {
229             log.trace("restricted type");
230          }
231       }
232       else if(type.isUnion())
233       {
234          if(log.isTraceEnabled())
235          {
236             log.trace("union of types");
237          }
238       }
239       else
240       {
241          throw new IllegalStateException JavaDoc("Simple type is not atomic, list, restriction or union!");
242       }
243
244       XsQName name = element.getName();
245       final String JavaDoc prefix = name.getPrefix();
246       String JavaDoc qName = (
247          prefix == null || prefix.length() == 0 ?
248          name.getLocalName() : prefix + ':' + name.getLocalName()
249          );
250
251       Object JavaDoc parent;
252       if(stack.isEmpty())
253       {
254          parent = provider.getRoot(this.root, name.getNamespaceURI(), name.getLocalName());
255          if(parent == null)
256          {
257             return;
258          }
259          char[] ch = parent.toString().toCharArray();
260          content.startElement(name.getNamespaceURI(), name.getLocalName(), qName, attrs);
261          content.characters(ch, 0, ch.length);
262          content.endElement(name.getNamespaceURI(), name.getLocalName(), qName);
263       }
264       else
265       {
266          parent = stack.peek();
267          Object JavaDoc value = provider.getElementValue(parent, name.getNamespaceURI(), name.getLocalName());
268
269          if(value != null)
270          {
271             char[] ch = value.toString().toCharArray();
272             content.startElement(name.getNamespaceURI(), name.getLocalName(), qName, attrs);
273             content.characters(ch, 0, ch.length);
274             content.endElement(name.getNamespaceURI(), name.getLocalName(), qName);
275          }
276       }
277    }
278
279    private final void processComplexType(XSElement element,
280                                          XSComplexType type,
281                                          AttributesImpl addedAttrs,
282                                          int maxOccurs)
283       throws SAXException JavaDoc
284    {
285       final XsQName xsName = element.getName();
286
287       Object JavaDoc parent;
288       boolean popRoot = false;
289       if(stack.isEmpty())
290       {
291          parent = provider.getRoot(this.root, xsName.getNamespaceURI(), xsName.getLocalName());
292          if(parent == null)
293          {
294             return;
295          }
296
297          AttributesImpl attrs = addedAttrs;
298          if(type.getAttributes() != null)
299          {
300             if(attrs == null)
301             {
302                attrs = provideAttributes(type.getAttributes(), parent);
303             }
304             else
305             {
306                attrs.addAll(provideAttributes(type.getAttributes(), parent));
307             }
308          }
309
310          String JavaDoc qName = xsName.getPrefix() == null ?
311             xsName.getLocalName() :
312             xsName.getPrefix() + ":" + xsName.getLocalName();
313          content.startElement(xsName.getNamespaceURI(), xsName.getLocalName(), qName, attrs);
314
315          stack.push(parent);
316          popRoot = true;
317       }
318       else
319       {
320          parent = stack.peek();
321       }
322
323       // todo rewrite
324
Object JavaDoc children = null;
325       if(!popRoot)
326       {
327          children = provider.getChildren(parent, xsName.getNamespaceURI(), xsName.getLocalName());
328       }
329
330       if(children != null)
331       {
332          String JavaDoc qName = null;
333          if(maxOccurs == 1)
334          {
335             AttributesImpl attrs = addedAttrs;
336             if(type.getAttributes() != null)
337             {
338                if(attrs != null)
339                {
340                   attrs.addAll(provideAttributes(type.getAttributes(), parent));
341                }
342                else
343                {
344                   attrs = provideAttributes(type.getAttributes(), parent);
345                }
346             }
347
348             qName = xsName.getPrefix() == null ?
349                xsName.getLocalName() :
350                xsName.getPrefix() + ":" + xsName.getLocalName();
351             content.startElement(xsName.getNamespaceURI(), xsName.getLocalName(), qName, attrs);
352          }
353
354          handleChildren(element, type, children, addedAttrs, maxOccurs);
355
356          if(qName != null)
357          {
358             content.endElement(xsName.getNamespaceURI(), xsName.getLocalName(), qName);
359          }
360       }
361       else
362       {
363          if(type.hasSimpleContent())
364          {
365             processSimpleType(element, type.getSimpleContent().getType().getSimpleType(), null);
366          }
367          else
368          {
369             if(type.isEmpty())
370             {
371                final XsQName name = element.getName();
372
373                final Object JavaDoc value = provider.getElementValue(parent, name.getNamespaceURI(), name.getLocalName());
374                if(Boolean.TRUE.equals(value))
375                {
376                   final String JavaDoc prefix = name.getPrefix();
377                   String JavaDoc qName = (
378                      prefix == null || prefix.length() == 0 ?
379                      name.getLocalName() : prefix + ':' + name.getLocalName()
380                      );
381
382                   AttributesImpl ownAttrs = provideAttributes(type.getAttributes(), parent);
383                   if(ownAttrs != null)
384                   {
385                      if(addedAttrs != null)
386                      {
387                         ownAttrs.addAll(ownAttrs);
388                      }
389                   }
390                   else
391                   {
392                      ownAttrs = addedAttrs;
393                   }
394
395                   content.startElement(name.getNamespaceURI(), name.getLocalName(), qName, ownAttrs);
396                   content.endElement(name.getNamespaceURI(), name.getLocalName(), qName);
397                }
398             }
399             else
400             {
401                final XSParticle particle = type.getParticle();
402                if(particle != null)
403                {
404                   processParticle(particle);
405                }
406                else
407                {
408                   // anyType for example
409
}
410             }
411          }
412       }
413
414       if(popRoot)
415       {
416          stack.pop();
417          String JavaDoc qName = xsName.getPrefix() == null ?
418             xsName.getLocalName() :
419             xsName.getPrefix() + ":" + xsName.getLocalName();
420          content.endElement(xsName.getNamespaceURI(), xsName.getLocalName(), qName);
421       }
422    }
423
424    private void handleChildren(XSElement parent,
425                                XSComplexType type,
426                                Object JavaDoc children,
427                                AttributesImpl addedAttrs,
428                                int maxOccurs)
429       throws SAXException JavaDoc
430    {
431       if(children != null)
432       {
433          if(children instanceof List JavaDoc)
434          {
435             handleChildrenList(parent, type, (List JavaDoc)children, addedAttrs, maxOccurs);
436          }
437          else if(children instanceof Collection JavaDoc)
438          {
439             handleChildrenIterator(parent, type, ((Collection JavaDoc)children).iterator(), addedAttrs, maxOccurs);
440          }
441          else if(children instanceof Iterator JavaDoc)
442          {
443             handleChildrenIterator(parent, type, (Iterator JavaDoc)children, addedAttrs, maxOccurs);
444          }
445          else if(children.getClass().isArray())
446          {
447             handleChildrenArray(parent, type, (Object JavaDoc[])children, addedAttrs, maxOccurs);
448          }
449          else
450          {
451             handleChild(parent, type, children, addedAttrs);
452          }
453       }
454    }
455
456    private AttributesImpl provideAttributes(XSAttributable[] xsAttrs, Object JavaDoc container)
457    {
458       AttributesImpl attrs = new AttributesImpl(xsAttrs.length);
459       for(int i = 0; i < xsAttrs.length; ++i)
460       {
461          final XSAttributable attributable = xsAttrs[i];
462          if(attributable instanceof XSAttribute)
463          {
464             final XSAttribute attr = (XSAttribute)attributable;
465
466             final XsQName attrQName = attr.getName();
467             final Object JavaDoc attrValue = provider.getAttributeValue(container,
468                attrQName.getNamespaceURI(),
469                attrQName.getLocalName()
470             );
471
472             if(attrValue != null)
473             {
474                final String JavaDoc prefix = attrQName.getPrefix();
475                String JavaDoc qName = (
476                   prefix == null || prefix.length() == 0 ?
477                   attrQName.getLocalName() : attrQName.getPrefix() + ':' + attrQName.getLocalName()
478                   );
479
480                attrs.add(attrQName.getNamespaceURI(),
481                   attrQName.getLocalName(),
482                   qName,
483                   attr.getType().getName().getLocalName(),
484                   attrValue.toString()
485                );
486             }
487             else
488             {
489                log.info("no val for attr " + attrQName.getLocalName() + ", container=" + container);
490             }
491          }
492       }
493       return attrs;
494    }
495
496    private final void processParticle(XSParticle particle) throws SAXException JavaDoc
497    {
498       if(particle.isElement())
499       {
500          XSElement element = particle.getElement();
501          processElement(element, null, particle.getMaxOccurs());
502       }
503       else if(particle.isGroup())
504       {
505          XSGroup group = particle.getGroup();
506          processGroup(group);
507       }
508       else if(particle.isWildcard())
509       {
510          if(log.isTraceEnabled())
511          {
512             log.trace("any");
513          }
514       }
515       else
516       {
517          throw new IllegalStateException JavaDoc("Particle is not an element, group or wildcard!");
518       }
519    }
520
521    private final void processGroup(XSGroup group) throws SAXException JavaDoc
522    {
523       if(group.isSequence())
524       {
525       }
526       else if(group.isChoice())
527       {
528       }
529       else if(group.isAll())
530       {
531       }
532       else
533       {
534          throw new IllegalStateException JavaDoc("Group is not a sequence, choice or all!");
535       }
536
537       XSParticle[] particles = group.getParticles();
538       for(int i = 0; i < particles.length; ++i)
539       {
540          XSParticle particle = particles[i];
541          processParticle(particle);
542       }
543    }
544
545    private void handleChildrenList(XSElement parent,
546                                    XSComplexType type,
547                                    List JavaDoc children,
548                                    AttributesImpl addedAttrs,
549                                    int maxOccurs)
550       throws SAXException JavaDoc
551    {
552       /*
553       for(int i = 0; i < children.size(); ++i)
554       {
555          handleChild(parent, type, children.get(i), addedAttrs);
556       }
557       */

558       handleChildrenIterator(parent, type, children.iterator(), addedAttrs, maxOccurs);
559    }
560
561    private void handleChildrenIterator(XSElement parent,
562                                        XSComplexType type,
563                                        Iterator JavaDoc children,
564                                        AttributesImpl addedAttrs,
565                                        int maxOccurs)
566       throws SAXException JavaDoc
567    {
568       //XSParticle particle = type.getParticle();
569
XsQName name = parent.getName();
570       String JavaDoc qName = null;
571       if(maxOccurs == -1 || maxOccurs > 0)
572       {
573          qName = name.getPrefix() == null ? name.getLocalName() : name.getPrefix() + ':' + name.getLocalName();
574       }
575
576       while(children.hasNext())
577       {
578          Object JavaDoc child = children.next();
579
580          if(qName != null)
581          {
582             AttributesImpl attrs = addedAttrs;
583             if(type.getAttributes() != null)
584             {
585                if(attrs != null)
586                {
587                   attrs.addAll(provideAttributes(type.getAttributes(), child));
588                }
589                else
590                {
591                   attrs = provideAttributes(type.getAttributes(), child);
592                }
593             }
594
595             content.startElement(name.getNamespaceURI(), name.getLocalName(), qName, attrs);
596          }
597
598          handleChild(parent, type, child, addedAttrs);
599
600          if(qName != null)
601          {
602             content.endElement(name.getNamespaceURI(), name.getLocalName(), qName);
603          }
604       }
605    }
606
607    private void handleChildrenArray(XSElement parent,
608                                     XSComplexType type,
609                                     Object JavaDoc[] children,
610                                     AttributesImpl addedAttrs,
611                                     int maxOccurs)
612       throws SAXException JavaDoc
613    {
614       /*
615       for(int i = 0; i < children.length; ++i)
616       {
617          handleChild(parent, type, children[i], addedAttrs);
618       }
619       */

620       handleChildrenIterator(parent, type, Arrays.asList(children).iterator(), addedAttrs, maxOccurs);
621    }
622
623    private void handleChild(XSElement parent, XSComplexType type, Object JavaDoc child, AttributesImpl addedAttrs)
624       throws SAXException JavaDoc
625    {
626       stack.push(child);
627
628       final XSAttributable[] xsAttrs = type.getAttributes();
629       AttributesImpl ownAttrs = (xsAttrs == null ? null : provideAttributes(xsAttrs, child));
630       if(ownAttrs != null)
631       {
632          if(addedAttrs != null)
633          {
634             ownAttrs.addAll(addedAttrs);
635          }
636       }
637       else
638       {
639          ownAttrs = addedAttrs;
640       }
641
642       if(type.hasSimpleContent())
643       {
644          processSimpleType(parent, type.getSimpleContent().getType().getSimpleType(), ownAttrs);
645       }
646       else
647       {
648          if(!type.isEmpty() && type.getParticle() != null)
649          {
650             processParticle(type.getParticle());
651          }
652          else
653          {
654             ClassMapping mapping = getClassMapping(child.getClass());
655
656             InputSource JavaDoc source = new InputSource JavaDoc(mapping.schemaUrl);
657
658             XSParser xsParser = new XSParser();
659             xsParser.setValidating(false);
660             XSSchema xsSchema;
661             try
662             {
663                xsSchema = xsParser.parse(source);
664             }
665             catch(Exception JavaDoc e)
666             {
667                log.error(e);
668                throw new IllegalStateException JavaDoc(e.getMessage());
669             }
670
671             XsQName rootName = new XsQName(mapping.namespaceUri, mapping.root);
672             XSElement root = xsSchema.getElement(rootName);
673             // name with the prefix
674
rootName = root.getName();
675
676             String JavaDoc rootPrefix = rootName.getPrefix();
677             String JavaDoc rootQName = (rootPrefix == null || rootPrefix.length() == 0 ?
678                rootName.getLocalName() : rootPrefix + ':' + rootName.getLocalName()
679                );
680
681             Stack oldStack = this.stack;
682             this.stack = new StackImpl();
683             Object JavaDoc oldRoot = this.root;
684             this.root = child;
685             GenericObjectModelProvider oldProvider = this.provider;
686             this.provider = mapping.provider;
687             content.startElement(rootName.getNamespaceURI(), rootName.getLocalName(), rootQName, addedAttrs);
688
689             processElement(root, addedAttrs, 1);
690
691             content.endElement(rootName.getNamespaceURI(), rootName.getLocalName(), rootQName);
692             this.root = oldRoot;
693             this.stack = oldStack;
694             this.provider = oldProvider;
695          }
696       }
697
698       stack.pop();
699    }
700
701    /*
702    private static String getQName(String prefix, String localName)
703    {
704       return (prefix == null || prefix.length() == 0 ? localName : prefix + ':' + localName);
705    }
706    */

707 }
708
Popular Tags