KickJava   Java API By Example, From Geeks To Geeks.

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

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

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

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

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

131    public void declareNamespace(String JavaDoc prefix, String JavaDoc uri)
132    {
133       prefixByUri.put(uri, prefix);
134    }
135
136    /**
137     * Adds an attribute to the top most elements.
138     * First, we check whether there is a namespace associated with the passed in prefix.
139     * If the prefix was not declared, an exception is thrown.
140     *
141     * @param prefix the prefix of the attribute to be declared
142     * @param localName local name of the attribute
143     * @param type the type of the attribute
144     * @param value the value of the attribute
145     */

146    public void addAttribute(String JavaDoc prefix, String JavaDoc localName, String JavaDoc type, String JavaDoc value)
147    {
148       // todo what was that?..
149
/*
150       final String uri;
151       if(prefix != null && prefix.length() > 0)
152       {
153          uri = (String)prefixByUri.get(prefix);
154          if(uri == null)
155          {
156             throw new IllegalStateException("Namespace prefix " + prefix + " is not declared. Use declareNamespace().");
157          }
158       }
159       else
160       {
161          uri = null;
162       }
163       */

164    }
165
166    /**
167     * Adds an attribute to the top most elements declaring namespace prefix if it is not yet declared.
168     *
169     * @param namespaceUri attribute's namespace URI
170     * @param prefix attribute's prefix
171     * @param localName attribute's local name
172     * @param type attribute's type
173     * @param value attribute's value
174     */

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

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

579       handleChildrenIterator(parent, type, children.iterator(), maxOccurs);
580    }
581
582    private void handleChildrenIterator(XSElement parent,
583                                        XSComplexType type,
584                                        Iterator JavaDoc children,
585                                        int maxOccurs)
586       throws SAXException JavaDoc
587    {
588       //XSParticle particle = type.getParticle();
589
XsQName name = parent.getName();
590       String JavaDoc qName = null;
591       if(maxOccurs == -1 || maxOccurs > 0)
592       {
593          qName = name.getPrefix() == null ? name.getLocalName() : name.getPrefix() + ':' + name.getLocalName();
594       }
595
596       while(children.hasNext())
597       {
598          Object JavaDoc child = children.next();
599
600          if(qName != null)
601          {
602             AttributesImpl attrs = null;
603             if(type.getAttributes() != null)
604             {
605                if(attrs != null)
606                {
607                   attrs.addAll(provideAttributes(type.getAttributes(), child));
608                }
609                else
610                {
611                   attrs = provideAttributes(type.getAttributes(), child);
612                }
613             }
614
615             content.startElement(name.getNamespaceURI(), name.getLocalName(), qName, attrs);
616          }
617
618          handleChild(parent, type, child, false);
619
620          if(qName != null)
621          {
622             content.endElement(name.getNamespaceURI(), name.getLocalName(), qName);
623          }
624       }
625    }
626
627    private void handleChildrenArray(XSElement parent,
628                                     XSComplexType type,
629                                     Object JavaDoc[] children,
630                                     int maxOccurs)
631       throws SAXException JavaDoc
632    {
633       /*
634       for(int i = 0; i < children.length; ++i)
635       {
636          handleChild(parent, type, children[i], addedAttrs);
637       }
638       */

639       handleChildrenIterator(parent, type, Arrays.asList(children).iterator(), maxOccurs);
640    }
641
642    private void handleChild(XSElement parent, XSComplexType type, Object JavaDoc child, boolean declareNs)
643       throws SAXException JavaDoc
644    {
645       stack.push(child);
646
647       final XSAttributable[] xsAttrs = type.getAttributes();
648       AttributesImpl ownAttrs = (xsAttrs == null ? null : provideAttributes(xsAttrs, child));
649
650       if(type.hasSimpleContent())
651       {
652          processSimpleType(parent, type.getSimpleContent().getType(), ownAttrs, declareNs);
653       }
654       else
655       {
656          if(!type.isEmpty() && type.getParticle() != null)
657          {
658             processParticle(type.getParticle());
659          }
660          else
661          {
662             ClassMapping mapping = getClassMapping(child.getClass());
663
664             InputSource JavaDoc source = new InputSource JavaDoc(mapping.schemaUrl);
665
666             XSParser xsParser = new XSParser();
667             xsParser.setValidating(false);
668             XSSchema xsSchema;
669             try
670             {
671                xsSchema = xsParser.parse(source);
672             }
673             catch(Exception JavaDoc e)
674             {
675                log.error(e);
676                throw new IllegalStateException JavaDoc(e.getMessage());
677             }
678
679             XsQName rootName = new XsQName(mapping.namespaceUri, mapping.root);
680             XSElement root = xsSchema.getElement(rootName);
681             // name with the prefix
682
rootName = root.getName();
683
684             String JavaDoc rootPrefix = rootName.getPrefix();
685             String JavaDoc rootQName = (rootPrefix == null || rootPrefix.length() == 0 ?
686                rootName.getLocalName() : rootPrefix + ':' + rootName.getLocalName()
687                );
688
689             Stack oldStack = this.stack;
690             this.stack = new StackImpl();
691             Object JavaDoc oldRoot = this.root;
692             this.root = child;
693             GenericObjectModelProvider oldProvider = this.provider;
694             this.provider = mapping.provider;
695             content.startElement(rootName.getNamespaceURI(), rootName.getLocalName(), rootQName, null);
696
697             processElement(root, 1, false);
698
699             content.endElement(rootName.getNamespaceURI(), rootName.getLocalName(), rootQName);
700             this.root = oldRoot;
701             this.stack = oldStack;
702             this.provider = oldProvider;
703          }
704       }
705
706       stack.pop();
707    }
708
709    private void declareNs(AttributesImpl ownAttrs)
710    {
711       for(Iterator JavaDoc i = prefixByUri.entrySet().iterator(); i.hasNext();)
712       {
713          Map.Entry JavaDoc entry = (Map.Entry JavaDoc)i.next();
714          String JavaDoc localName = (String JavaDoc)entry.getValue();
715          ownAttrs.add(null,
716             localName,
717             localName == null ? "xmlns" : "xmlns:" + localName,
718             null,
719             (String JavaDoc)entry.getKey()
720          );
721       }
722    }
723
724    /*
725    private static String getQName(String prefix, String localName)
726    {
727       return (prefix == null || prefix.length() == 0 ? localName : prefix + ':' + localName);
728    }
729    */

730 }
731
Popular Tags