KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > runtime > impl > MarshallingContext


1 /*
2 Copyright (c) 2002-2004, Dennis M. Sosnoski.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.runtime.impl;
30
31 import java.io.*;
32 import java.util.*;
33
34 import org.jibx.runtime.*;
35 import org.jibx.runtime.ICharacterEscaper;
36 import org.jibx.runtime.IMarshallable;
37 import org.jibx.runtime.IMarshaller;
38 import org.jibx.runtime.IMarshallingContext;
39 import org.jibx.runtime.JiBXException;
40
41 /**
42  * JiBX serializer supplying convenience methods for marshalling. Most of these
43  * methods are designed for use in code generated by the binding generator.
44  *
45  * @author Dennis M. Sosnoski
46  * @version 1.0
47  */

48
49 public class MarshallingContext implements IMarshallingContext
50 {
51     /** Fixed XML namespace. */
52     public static final String JavaDoc XML_NAMESPACE =
53         "http://www.w3.org/XML/1998/namespace";
54         
55     /** Starting size for object stack. */
56     protected static final int INITIAL_STACK_SIZE = 20;
57         
58     /** Names of classes included in mapping definition. */
59     protected String JavaDoc[] m_classes;
60     
61     /** Number of classes with global marshallers. */
62     protected int m_globalCount;
63     
64     /** Marshaller classes for mapping definition (<code>null</code> for
65      mappings out of context). */

66     protected String JavaDoc[] m_marshallerClasses;
67     
68     /** Marshallers for classes in mapping definition (lazy create of actual
69      marshaller instances) */

70     protected IMarshaller[] m_marshallers;
71     
72     /** URIs for namespaces used in binding. */
73     protected String JavaDoc[] m_uris;
74     
75     /** Map from URI to index number. */
76     protected HashMap m_uriMap;
77     
78     /** Current marshalling stack depth. */
79     protected int m_stackDepth;
80     
81     /** Stack of objects being marshalled. */
82     protected Object JavaDoc[] m_objectStack;
83     
84     /** Indent character count per level. */
85     private int m_indentCount;
86     
87     /** Character sequence for end of line. */
88     private String JavaDoc m_newLine;
89     
90     /** Character used for indenting. */
91     private char m_indentChar;
92     
93     /** Shared map from IDs to objects. This is not used directly by the
94       marshalling code, but is available for user extensions (lazy create). */

95     private HashMap m_idMap;
96     
97     /** Output document handler. */
98     protected IXMLWriter m_writer;
99     
100     /**
101      * Constructor.
102      *
103      * @param classes ordered array of class names included in mapping
104      * definition (reference kept, must be constant)
105      * @param mcs names of marshaller classes for indexes with fixed marshallers
106      * (as opposed to mapping slots, which may be overridden; reference kept,
107      * must be constant)
108      * @param uris ordered array of URIs for namespaces used in binding (must
109      * be constant; the value in position 0 must always be the empty string "",
110      * and the value in position 1 must always be the XML namespace
111      * "http://www.w3.org/XML/1998/namespace")
112      */

113     
114     public MarshallingContext(String JavaDoc[] classes, String JavaDoc[] mcs, String JavaDoc[] uris) {
115         m_classes = classes;
116         m_globalCount = mcs.length;
117         m_marshallers = new IMarshaller[classes.length];
118         m_marshallerClasses = new String JavaDoc[classes.length];
119         System.arraycopy(mcs, 0, m_marshallerClasses, 0, mcs.length);
120         m_uris = uris;
121         m_objectStack = new Object JavaDoc[INITIAL_STACK_SIZE];
122         m_indentCount = -1;
123         m_indentChar = ' ';
124         m_newLine = "\n";
125     }
126     
127     /**
128      * Create character escaper for encoding.
129      *
130      * @param enc document output encoding, or <code>null</code> for default
131      * @return character escaper for encoding
132      * @throws JiBXException if error creating setting output
133      */

134
135     private ICharacterEscaper createEscaper(String JavaDoc enc) throws JiBXException {
136         if (enc.equalsIgnoreCase("UTF-8")) {
137             return UTF8Escaper.getInstance();
138         } else if (enc.equalsIgnoreCase("ISO-8859-1")) {
139             return ISO88591Escaper.getInstance();
140         } else if (enc.equalsIgnoreCase("US-ASCII")) {
141             return USASCIIEscaper.getInstance();
142         } else {
143             throw new JiBXException
144                 ("No character escaper defined for encoding " + enc);
145         }
146     }
147     
148     /**
149      * Set output stream with encoding and escaper. This forces handling of the
150      * output stream to use the Java character encoding support with the
151      * supplied escaper.
152      *
153      * @param outs stream for document data output
154      * @param enc document output encoding, or <code>null</code> uses UTF-8
155      * default
156      * @param esc escaper for writing characters to stream
157      * @throws JiBXException if error setting output
158      */

159     
160     public void setOutput(OutputStream outs, String JavaDoc enc, ICharacterEscaper esc)
161         throws JiBXException {
162         try {
163             if (enc == null) {
164                 enc = "UTF-8";
165             }
166                 
167             // handle any other encodings using library support
168
if (!(m_writer instanceof GenericXMLWriter)) {
169                 m_writer = new GenericXMLWriter(m_uris);
170                 m_writer.setIndentSpaces(m_indentCount, m_newLine,
171                      m_indentChar);
172             }
173             Writer writer = new BufferedWriter
174                 (new OutputStreamWriter(outs, enc));
175             ((GenericXMLWriter)m_writer).setOutput(writer,esc);
176             reset();
177             
178         } catch (IOException ex) {
179             throw new JiBXException("Error setting output", ex);
180         }
181     }
182     
183     /**
184      * Set output stream and encoding.
185      *
186      * @param outs stream for document data output
187      * @param enc document output encoding, or <code>null</code> for default
188      * @throws JiBXException if error creating setting output
189      */

190     
191     public void setOutput(OutputStream outs, String JavaDoc enc) throws JiBXException {
192         if (enc == null) {
193             enc = "UTF-8";
194         }
195         if ("UTF-8".equalsIgnoreCase(enc)) {
196                 
197             // handle UTF-8 output to stream directly
198
if (!(m_writer instanceof UTF8StreamWriter)) {
199                 m_writer = new UTF8StreamWriter(m_uris);
200                 m_writer.setIndentSpaces(m_indentCount, m_newLine,
201                      m_indentChar);
202             }
203             ((UTF8StreamWriter)m_writer).setOutput(outs);
204             reset();
205                 
206         } else if ("ISO-8859-1".equalsIgnoreCase(enc)) {
207                 
208             // handle ISO-8859-1 output to stream directly
209
if (!(m_writer instanceof ISO88591StreamWriter)) {
210                 m_writer = new ISO88591StreamWriter(m_uris);
211                 m_writer.setIndentSpaces(m_indentCount, m_newLine,
212                      m_indentChar);
213             }
214             ((ISO88591StreamWriter)m_writer).setOutput(outs);
215             reset();
216                 
217         } else {
218             setOutput(outs, enc, createEscaper(enc));
219         }
220     }
221     
222     /**
223      * Set output writer and escaper.
224      *
225      * @param outw writer for document data output
226      * @param esc escaper for writing characters
227      */

228     
229     public void setOutput(Writer outw, ICharacterEscaper esc) {
230         if (!(m_writer instanceof GenericXMLWriter)) {
231             m_writer = new GenericXMLWriter(m_uris);
232             m_writer.setIndentSpaces(m_indentCount, m_newLine,
233                  m_indentChar);
234         }
235         ((GenericXMLWriter)m_writer).setOutput(outw, esc);
236         reset();
237     }
238     
239     /**
240      * Set output writer.
241      *
242      * @param outw writer for document data output
243      */

244     
245     public void setOutput(Writer outw) {
246         setOutput(outw, UTF8Escaper.getInstance());
247     }
248
249     /**
250      * Get the writer being used for output.
251      *
252      * @return XML writer used for output
253      */

254
255     public IXMLWriter getXmlWriter() {
256         return m_writer;
257     }
258
259     /**
260      * Set the writer being used for output.
261      *
262      * @param xwrite XML writer used for output
263      */

264
265     public void setXmlWriter(IXMLWriter xwrite) {
266         m_writer = xwrite;
267     }
268     
269     /**
270      * Get current nesting indent spaces. This returns the number of spaces used
271      * to show indenting, if used.
272      *
273      * @return number of spaces indented per level, or negative if indentation
274      * disabled
275      */

276     
277     public int getIndent() {
278         return m_indentCount;
279     }
280     
281     /**
282      * Set nesting indent spaces. This is advisory only, and implementations of
283      * this interface are free to ignore it. The intent is to indicate that the
284      * generated output should use indenting to illustrate element nesting.
285      *
286      * @param count number of spaces to indent per level, or disable
287      * indentation if negative
288      */

289     
290     public void setIndent(int count) {
291         if (m_writer != null) {
292             m_writer.setIndentSpaces(count, m_newLine, m_indentChar);
293         }
294         m_indentCount = count;
295     }
296     
297     /**
298      * Set nesting indentation. This is advisory only, and implementations of
299      * this interface are free to ignore it. The intent is to indicate that the
300      * generated output should use indenting to illustrate element nesting.
301      *
302      * @param count number of character to indent per level, or disable
303      * indentation if negative (zero means new line only)
304      * @param newline sequence of characters used for a line ending
305      * (<code>null</code> means use the single character '\n')
306      * @param indent whitespace character used for indentation
307      */

308     
309     public void setIndent(int count, String JavaDoc newline, char indent) {
310         if (m_writer != null) {
311             m_writer.setIndentSpaces(count, newline, indent);
312         }
313         m_indentCount = count;
314         m_newLine = newline;
315         m_indentChar = indent;
316     }
317
318     /**
319      * Initializes the context to use the same marshalled text destination and
320      * parameters as another marshalling context. This method is designed for
321      * use when an initial context needs to create and invoke a secondary
322      * context (generally from a different binding) in the course of an
323      * marshalling operation.
324      *
325      * @param parent context supplying target for marshalled document text
326      */

327
328     public void setFromContext(MarshallingContext parent) {
329         reset();
330         m_writer = parent.m_writer;
331     }
332     
333     /**
334      * Reset to initial state for reuse. The context is serially reusable,
335      * as long as this method is called to clear any retained state information
336      * between uses. It is automatically called when output is set.
337      */

338     
339     public void reset() {
340         if (m_writer != null) {
341             m_writer.reset();
342         }
343         for (int i = m_globalCount; i < m_marshallers.length; i++) {
344             m_marshallers[i] = null;
345         }
346         for (int i = 0; i < m_objectStack.length; i++) {
347             m_objectStack[i] = null;
348         }
349         m_stackDepth = 0;
350     }
351     
352     /**
353      * Get namespace URIs for mapping. This gets the full ordered array of
354      * namespaces known in the binding used for this marshalling, where the
355      * index number of each namespace URI is the namespace index used to lookup
356      * the prefix when marshalling a name in that namespace. The returned array
357      * must not be modified.
358      *
359      * @return array of namespaces
360      */

361     
362     public String JavaDoc[] getNamespaces() {
363         return m_uris;
364     }
365     
366     /**
367      * Start document. This can only be validly called immediately following
368      * one of the set output methods; otherwise the output document will be
369      * corrupt.
370      *
371      * @param enc document encoding, <code>null</code> if not specified
372      * @param alone standalone document flag, <code>null</code> if not
373      * specified
374      * @throws JiBXException on any error (possibly wrapping other exception)
375      */

376
377     public void startDocument(String JavaDoc enc, Boolean JavaDoc alone) throws JiBXException {
378         try {
379             String JavaDoc atext = null;
380             if (alone != null) {
381                 atext = alone.booleanValue() ? "yes" : "no";
382             }
383             m_writer.writeXMLDecl("1.0", enc, atext);
384         } catch (IOException ex) {
385             throw new JiBXException("Error writing marshalled document", ex);
386         }
387     }
388     
389     /**
390      * Start document with output stream and encoding. The effect is the same
391      * as from first setting the output stream and encoding, then making the
392      * call to start document.
393      *
394      * @param enc document encoding, <code>null</code> if not specified
395      * @param alone standalone document flag, <code>null</code> if not
396      * specified
397      * @param outs stream for document data output
398      * @throws JiBXException on any error (possibly wrapping other exception)
399      */

400
401     public void startDocument(String JavaDoc enc, Boolean JavaDoc alone, OutputStream outs)
402         throws JiBXException {
403         setOutput(outs, enc);
404         startDocument(enc, alone);
405     }
406     
407     /**
408      * Start document with writer. The effect is the same as from first
409      * setting the writer, then making the call to start document.
410      *
411      * @param enc document encoding, <code>null</code> if not specified
412      * @param alone standalone document flag, <code>null</code> if not
413      * specified
414      * @param outw writer for document data output
415      * @throws JiBXException on any error (possibly wrapping other exception)
416      */

417
418     public void startDocument(String JavaDoc enc, Boolean JavaDoc alone, Writer outw)
419         throws JiBXException {
420         setOutput(outw);
421         startDocument(enc, alone);
422     }
423     
424     /**
425      * End document. Finishes all output and closes the document. Note that if
426      * this is called with an imcomplete marshalling the result will not be
427      * well-formed XML.
428      *
429      * @throws JiBXException on any error (possibly wrapping other exception)
430      */

431
432     public void endDocument() throws JiBXException {
433         try {
434             m_writer.close();
435         } catch (IOException ex) {
436             throw new JiBXException("Error writing marshalled document", ex);
437         }
438     }
439
440     /**
441      * Build name with optional namespace. Just returns the appropriate
442      * name format.
443      *
444      * @param index namespace URI index number
445      * @param name local name part of name
446      * @return formatted name string
447      */

448     public String JavaDoc buildNameString(int index, String JavaDoc name) {
449         String JavaDoc ns = m_writer.getNamespaceUri(index);
450         if (ns == null || "".equals(ns)) {
451             return "\"" + name + "\"";
452         } else {
453             return "\"{" + ns + "}" + name + "\"";
454         }
455     }
456     
457     /**
458      * Generate start tag for element without attributes.
459      *
460      * @param index namespace URI index number
461      * @param name element name
462      * @return this context (to allow chained calls)
463      * @throws JiBXException on any error (possibly wrapping other exception)
464      */

465
466     public MarshallingContext startTag(int index, String JavaDoc name)
467         throws JiBXException {
468         try {
469             m_writer.startTagClosed(index, name);
470             return this;
471         } catch (IOException ex) {
472             throw new JiBXException("Error writing marshalled document", ex);
473         }
474     }
475     
476     /**
477      * Generate start tag for element with attributes. This only opens the start
478      * tag, allowing attributes to be added immediately following this call.
479      *
480      * @param index namespace URI index number
481      * @param name element name
482      * @return this context (to allow chained calls)
483      * @throws JiBXException on any error (possibly wrapping other exception)
484      */

485
486     public MarshallingContext startTagAttributes(int index, String JavaDoc name)
487         throws JiBXException {
488         try {
489             m_writer.startTagOpen(index, name);
490             return this;
491         } catch (IOException ex) {
492             throw new JiBXException("Error writing marshalled document", ex);
493         }
494     }
495     
496     /**
497      * Generate text attribute. This can only be used following an open start
498      * tag with attributes.
499      *
500      * @param index namespace URI index number
501      * @param name attribute name
502      * @param value text value for attribute
503      * @return this context (to allow chained calls)
504      * @throws JiBXException on any error (possibly wrapping other exception)
505      */

506
507     public MarshallingContext attribute(int index, String JavaDoc name, String JavaDoc value)
508         throws JiBXException {
509         try {
510             m_writer.addAttribute(index, name, value);
511             return this;
512         } catch (IOException ex) {
513             throw new JiBXException("Error writing marshalled document", ex);
514         } catch (Exception JavaDoc ex) {
515             throw new JiBXException("Exception while marshalling attribute " +
516                 buildNameString(index, name), ex);
517         }
518     }
519     
520     /**
521      * Generate integer attribute. This can only be used following an open start
522      * tag.
523      *
524      * @param index namespace URI index number
525      * @param name attribute name
526      * @param value integer value for attribute
527      * @return this context (to allow chained calls)
528      * @throws JiBXException on any error (possibly wrapping other exception)
529      */

530
531     public MarshallingContext attribute(int index, String JavaDoc name, int value)
532         throws JiBXException {
533         return attribute(index, name, Integer.toString(value));
534     }
535     
536     /**
537      * Generate enumeration attribute. The actual text to be written is obtained
538      * by indexing into the supplied array of values. This can only be used
539      * following an open start tag.
540      *
541      * @param index namespace URI index number
542      * @param name attribute name
543      * @param value integer enumeration value (zero-based)
544      * @param table text values in enumeration
545      * @return this context (to allow chained calls)
546      * @throws JiBXException on any error (possibly wrapping other exception)
547      */

548
549     public MarshallingContext attribute(int index, String JavaDoc name, int value,
550         String JavaDoc[] table) throws JiBXException {
551         try {
552             return attribute(index, name, table[value]);
553         } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
554             throw new JiBXException("Enumeration value of " + value +
555                 " is outside to allowed range of 0 to " + table.length);
556         }
557     }
558     
559     /**
560      * Close start tag with content to follow.
561      *
562      * @return this context (to allow chained calls)
563      * @throws JiBXException on any error (possibly wrapping other exception)
564      */

565
566     public MarshallingContext closeStartContent() throws JiBXException {
567         try {
568             m_writer.closeStartTag();
569             return this;
570         } catch (IOException ex) {
571             throw new JiBXException("Error writing marshalled document", ex);
572         }
573     }
574     
575     /**
576      * Close start tag with no content (empty tag).
577      *
578      * @return this context (to allow chained calls)
579      * @throws JiBXException on any error (possibly wrapping other exception)
580      */

581
582     public MarshallingContext closeStartEmpty() throws JiBXException {
583         try {
584             m_writer.closeEmptyTag();
585             return this;
586         } catch (IOException ex) {
587             throw new JiBXException("Error writing marshalled document", ex);
588         }
589     }
590     
591     /**
592      * Add text content to current element.
593      *
594      * @param value text element content
595      * @return this context (to allow chained calls)
596      * @throws JiBXException on any error (possibly wrapping other exception)
597      */

598
599     public MarshallingContext content(String JavaDoc value) throws JiBXException {
600         try {
601             m_writer.writeTextContent(value);
602             return this;
603         } catch (IOException ex) {
604             throw new JiBXException("Error writing marshalled document", ex);
605         }
606     }
607     
608     /**
609      * Add integer content to current element.
610      *
611      * @param value integer element content
612      * @return this context (to allow chained calls)
613      * @throws JiBXException on any error (possibly wrapping other exception)
614      */

615
616     public MarshallingContext content(int value) throws JiBXException {
617         content(Integer.toString(value));
618         return this;
619     }
620     
621     /**
622      * Add enumeration content to current element. The actual text to be
623      * written is obtained by indexing into the supplied array of values.
624      *
625      * @param value integer enumeration value (zero-based)
626      * @param table text values in enumeration
627      * @return this context (to allow chained calls)
628      * @throws JiBXException on any error (possibly wrapping other exception)
629      */

630
631     public MarshallingContext content(int value, String JavaDoc[] table)
632         throws JiBXException {
633         try {
634             content(table[value]);
635             return this;
636         } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
637             throw new JiBXException("Enumeration value of " + value +
638                 " is outside to allowed range of 0 to " + table.length);
639         }
640     }
641     
642     /**
643      * Generate end tag for element.
644      *
645      * @param index namespace URI index number
646      * @param name element name
647      * @return this context (to allow chained calls)
648      * @throws JiBXException on any error (possibly wrapping other exception)
649      */

650
651     public MarshallingContext endTag(int index, String JavaDoc name)
652         throws JiBXException {
653         try {
654             m_writer.endTag(index, name);
655             return this;
656         } catch (IOException ex) {
657             throw new JiBXException("Error writing marshalled document", ex);
658         }
659     }
660
661     /**
662      * Generate complete element with text content.
663      *
664      * @param index namespace URI index number
665      * @param name element name
666      * @param value text element content
667      * @return this context (to allow chained calls)
668      * @throws JiBXException on any error (possibly wrapping other exception)
669      */

670
671     public MarshallingContext element(int index, String JavaDoc name, String JavaDoc value)
672         throws JiBXException {
673         try {
674             m_writer.startTagClosed(index, name);
675             m_writer.writeTextContent(value);
676             m_writer.endTag(index, name);
677             return this;
678         } catch (IOException ex) {
679             throw new JiBXException("Error writing marshalled document", ex);
680         } catch (Exception JavaDoc ex) {
681             throw new JiBXException("Exception while marshalling element " +
682                 buildNameString(index, name), ex);
683         }
684     }
685     
686     /**
687      * Generate complete element with integer content.
688      *
689      * @param index namespace URI index number
690      * @param name element name
691      * @param value integer element content
692      * @return this context (to allow chained calls)
693      * @throws JiBXException on any error (possibly wrapping other exception)
694      */

695
696     public MarshallingContext element(int index, String JavaDoc name, int value)
697         throws JiBXException {
698         return element(index, name, Integer.toString(value));
699     }
700     
701     /**
702      * Generate complete element with enumeration content. The actual text to be
703      * written is obtained by indexing into the supplied array of values.
704      *
705      * @param index namespace URI index number
706      * @param name element name
707      * @param value integer enumeration value (zero-based)
708      * @param table text values in enumeration
709      * @return this context (to allow chained calls)
710      * @throws JiBXException on any error (possibly wrapping other exception)
711      */

712
713     public MarshallingContext element(int index, String JavaDoc name, int value,
714         String JavaDoc[] table) throws JiBXException {
715         try {
716             return element(index, name, table[value]);
717         } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
718             throw new JiBXException("Enumeration value of " + value +
719                 " is outside to allowed range of 0 to " + table.length);
720         }
721     }
722     
723     /**
724      * Write CDATA text to document.
725      *
726      * @param text content value text
727      * @return this context (to allow chained calls)
728      * @throws IOException on error writing to document
729      */

730
731     public MarshallingContext writeCData(String JavaDoc text) throws IOException {
732         m_writer.writeCData(text);
733         return this;
734     }
735     
736     /**
737      * Write content value with character entity substitutions.
738      *
739      * @param text content value text
740      * @return this context (to allow chained calls)
741      * @throws IOException on error writing to document
742      */

743
744     public MarshallingContext writeContent(String JavaDoc text) throws IOException {
745         m_writer.writeTextContent(text);
746         return this;
747     }
748     
749     /**
750      * Marshal all items in a collection. This variation is for generic
751      * collections.
752      *
753      * @param col collection of items to be marshalled
754      * @return this context (to allow chained calls)
755      * @throws JiBXException on any error (possibly wrapping other exception)
756      */

757
758     public MarshallingContext marshalCollection(Collection col)
759         throws JiBXException {
760         Iterator iter = col.iterator();
761         while (iter.hasNext()) {
762             Object JavaDoc obj = iter.next();
763             if (obj instanceof IMarshallable) {
764                 ((IMarshallable)obj).marshal(this);
765             } else {
766                 throw new JiBXException
767                     ("Unmarshallable object of class " + obj.getClass() +
768                     " found in marshalling");
769             }
770         }
771         return this;
772     }
773     
774     /**
775      * Marshal all items in a collection. This variation is for ArrayList
776      * collections.
777      *
778      * @param col collection of items to be marshalled
779      * @return this context (to allow chained calls)
780      * @throws JiBXException on any error (possibly wrapping other exception)
781      */

782
783     public MarshallingContext marshalCollection(ArrayList col)
784         throws JiBXException {
785         for (int i = 0; i < col.size(); i++) {
786             Object JavaDoc obj = col.get(i);
787             if (obj instanceof IMarshallable) {
788                 ((IMarshallable)obj).marshal(this);
789             } else {
790                 throw new JiBXException
791                     ("Unmarshallable object of class " +
792                      obj.getClass().getName() + " found in marshalling");
793             }
794         }
795         return this;
796     }
797     
798     /**
799      * Marshal all items in a collection. This variation is for Vector
800      * collections.
801      *
802      * @param col collection of items to be marshalled
803      * @return this context (to allow chained calls)
804      * @throws JiBXException on any error (possibly wrapping other exception)
805      */

806
807     public MarshallingContext marshalCollection(Vector col)
808         throws JiBXException {
809         for (int i = 0; i < col.size(); i++) {
810             Object JavaDoc obj = col.elementAt(i);
811             if (obj instanceof IMarshallable) {
812                 ((IMarshallable)obj).marshal(this);
813             } else {
814                 throw new JiBXException
815                     ("Unmarshallable object of class " +
816                      obj.getClass().getName() + " found in marshalling");
817             }
818         }
819         return this;
820     }
821     
822     /**
823      * Define marshalling for class. Adds the marshalling definition using fixed
824      * indexes for each class, allowing direct lookup of the marshaller when
825      * multiple versions are defined.
826      *
827      * @param index class index for marshalling definition
828      * @param name marshaller class name handling
829      */

830     
831     public void addMarshalling(int index, String JavaDoc name) {
832         m_marshallerClasses[index] = name;
833     }
834     
835     /**
836      * Undefine marshalling for element. Removes the marshalling
837      * definition for a particular class index.
838      *
839      * @param index class index for marshalling definition
840      */

841     
842     public void removeMarshalling(int index) {
843         m_marshallers[index] = null;
844     }
845     
846     /**
847      * Generate start tag for element with namespaces. This creates the actual
848      * start tag, along with any necessary namespace declarations. Previously
849      * active namespace declarations are not duplicated. The tag is
850      * left incomplete, allowing other attributes to be added.
851      *
852      * TODO: Handle nested default namespaces declarations, prefixes for outers
853      *
854      * @param index namespace URI index number
855      * @param name element name
856      * @param nums array of namespace indexes defined by this element (must
857      * be constant, reference is kept until end of element)
858      * @param prefs array of namespace prefixes mapped by this element (no
859      * <code>null</code> values, use "" for default namespace declaration)
860      * @return this context (to allow chained calls)
861      * @throws JiBXException on any error (possibly wrapping other exception)
862      */

863
864     public MarshallingContext startTagNamespaces(int index, String JavaDoc name,
865         int[] nums, String JavaDoc[] prefs) throws JiBXException {
866         try {
867             m_writer.startTagNamespaces(index, name, nums, prefs);
868             return this;
869         } catch (IOException ex) {
870             throw new JiBXException("Error writing marshalled document", ex);
871         }
872     }
873     
874     /**
875      * Find the marshaller for a particular class index
876      * in the current context.
877      *
878      * @param index class index for marshalling definition
879      * @param name fully qualified name of class to be marshalled (used only
880      * for validation)
881      * @return marshalling handler for class
882      * @throws JiBXException on any error (possibly wrapping other exception)
883      */

884     
885     public IMarshaller getMarshaller(int index, String JavaDoc name)
886         throws JiBXException {
887         if (index >= m_classes.length || !name.equals(m_classes[index])) {
888             throw new JiBXException("Marshalling not defined for class " +
889                 name);
890         }
891         if (m_marshallers[index] == null) {
892             
893             // load the marshaller class and create an instance
894
Exception JavaDoc ex = null;
895             try {
896                 
897                 // first try loading class from context classloader
898
Class JavaDoc clas = null;
899                 String JavaDoc mname = m_marshallerClasses[index];
900                 ClassLoader JavaDoc loader =
901                     Thread.currentThread().getContextClassLoader();
902                 if (loader != null) {
903                     try {
904                         clas = loader.loadClass(mname);
905                     } catch (ClassNotFoundException JavaDoc e) { /* fall through */ }
906                 }
907                 if (clas == null) {
908                     
909                     // if not found, try the loader that loaded this class
910
clas = UnmarshallingContext.class.getClassLoader().
911                         loadClass(mname);
912                 }
913                 
914                 // create an instance of marshaller class
915
IMarshaller m = (IMarshaller)clas.newInstance();
916                 m_marshallers[index] = m;
917                 
918             } catch (ClassNotFoundException JavaDoc e) {
919                 ex = e;
920             } catch (InstantiationException JavaDoc e) {
921                 ex = e;
922             } catch (IllegalAccessException JavaDoc e) {
923                 ex = e;
924             } finally {
925                 if (ex != null) {
926                     throw new JiBXException
927                         ("Unable to create marshaller of class " +
928                         m_marshallerClasses[index], ex);
929                 }
930             }
931         }
932         return m_marshallers[index];
933     }
934     
935     /**
936      * Marshal document from root object. This internal method just verifies
937      * that the object is marshallable, then calls the marshal method on the
938      * object itself.
939      *
940      * @param root object at root of structure to be marshalled, which must have
941      * a top-level mapping in the binding
942      * @throws JiBXException on any error (possibly wrapping other exception)
943      */

944
945     protected void marshalRoot(Object JavaDoc root) throws JiBXException {
946         if (root instanceof IMarshallable) {
947             boolean valid = false;
948             IMarshallable mable = (IMarshallable)root;
949             int index = mable.JiBX_getIndex();
950             if (index < m_classes.length) {
951                 String JavaDoc cname = m_classes[index];
952                 Class JavaDoc mclass = mable.getClass();
953                 while (!mclass.getName().equals("java.lang.Object")) {
954                     if (mclass.getName().equals(cname)) {
955                         valid = true;
956                         break;
957                     } else {
958                         mclass = mclass.getSuperclass();
959                     }
960                 }
961             }
962             if (valid) {
963                 mable.marshal(this);
964             } else {
965                 throw new JiBXException("Supplied root object of class " +
966                     root.getClass().getName() +
967                     " is incompatible with the binding used for this context");
968             }
969         } else {
970             throw new JiBXException("Supplied root object of class " +
971                 root.getClass().getName() +
972                 " cannot be marshalled without top-level mapping");
973         }
974     }
975     
976     /**
977      * Marshal document from root object without XML declaration. This can only
978      * be validly called immediately following one of the set output methods;
979      * otherwise the output document will be corrupt. The effect of this method
980      * is the same as the sequence of a call to marshal the root object using
981      * this context followed by a call to {@link #endDocument}.
982      *
983      * @param root object at root of structure to be marshalled, which must have
984      * a top-level mapping in the binding
985      * @throws JiBXException on any error (possibly wrapping other exception)
986      */

987
988     public void marshalDocument(Object JavaDoc root) throws JiBXException {
989         marshalRoot(root);
990         endDocument();
991     }
992     
993     /**
994      * Marshal document from root object. This can only be validly called
995      * immediately following one of the set output methods; otherwise the output
996      * document will be corrupt. The effect of this method is the same as the
997      * sequence of a call to {@link #startDocument}, a call to marshal the root
998      * object using this context, and finally a call to {@link #endDocument}.
999      *
1000     * @param root object at root of structure to be marshalled, which must have
1001     * a top-level mapping in the binding
1002     * @param enc document encoding, <code>null</code> if not specified
1003     * @param alone standalone document flag, <code>null</code> if not
1004     * specified
1005     * @throws JiBXException on any error (possibly wrapping other exception)
1006     */

1007
1008    public void marshalDocument(Object JavaDoc root, String JavaDoc enc, Boolean JavaDoc alone)
1009        throws JiBXException {
1010        startDocument(enc, alone);
1011        marshalRoot(root);
1012        endDocument();
1013    }
1014    
1015    /**
1016     * Marshal document from root object to output stream with encoding. The
1017     * effect of this method is the same as the sequence of a call to {@link
1018     * #startDocument}, a call to marshal the root object using this context,
1019     * and finally a call to {@link #endDocument}.
1020     *
1021     * @param root object at root of structure to be marshalled, which must have
1022     * a top-level mapping in the binding
1023     * @param enc document encoding, <code>null</code> if not specified
1024     * @param alone standalone document flag, <code>null</code> if not
1025     * specified
1026     * @param outs stream for document data output
1027     * @throws JiBXException on any error (possibly wrapping other exception)
1028     */

1029
1030    public void marshalDocument(Object JavaDoc root, String JavaDoc enc, Boolean JavaDoc alone,
1031        OutputStream outs) throws JiBXException {
1032        startDocument(enc, alone, outs);
1033        marshalRoot(root);
1034        endDocument();
1035    }
1036    
1037    /**
1038     * Marshal document from root object to writer. The effect of this method
1039     * is the same as the sequence of a call to {@link #startDocument}, a call
1040     * to marshal the root object using this context, and finally a call to
1041     * {@link #endDocument}.
1042     *
1043     * @param root object at root of structure to be marshalled, which must have
1044     * a top-level mapping in the binding
1045     * @param enc document encoding, <code>null</code> if not specified
1046     * @param alone standalone document flag, <code>null</code> if not
1047     * specified
1048     * @param outw writer for document data output
1049     * @throws JiBXException on any error (possibly wrapping other exception)
1050     */

1051
1052    public void marshalDocument(Object JavaDoc root, String JavaDoc enc, Boolean JavaDoc alone,
1053        Writer outw) throws JiBXException {
1054        startDocument(enc, alone, outw);
1055        marshalRoot(root);
1056        endDocument();
1057    }
1058    
1059    /**
1060     * Get shared ID map. The ID map returned is not used directly by the
1061     * marshalling code, but is provided to support user extensions.
1062     *
1063     * @return ID map
1064     */

1065    
1066    public HashMap getIdMap() {
1067        if (m_idMap == null) {
1068            m_idMap = new HashMap();
1069        }
1070        return m_idMap;
1071    }
1072
1073    /**
1074     * Push created object to marshalling stack. This must be called before
1075     * beginning the marshalling of the object. It is only called for objects
1076     * with structure, not for those converted directly to and from text.
1077     *
1078     * @param obj object being marshalled
1079     */

1080
1081    public void pushObject(Object JavaDoc obj) {
1082        int depth = m_stackDepth;
1083        if (depth >= m_objectStack.length) {
1084            Object JavaDoc[] stack = new Object JavaDoc[depth*2];
1085            System.arraycopy(m_objectStack, 0, stack, 0, depth);
1086            m_objectStack = stack;
1087        }
1088        m_objectStack[depth] = obj;
1089        m_stackDepth++;
1090    }
1091
1092    /**
1093     * Pop marshalled object from stack.
1094     *
1095     * @throws JiBXException if no object on stack
1096     */

1097
1098    public void popObject() throws JiBXException {
1099        if (m_stackDepth > 0) {
1100            --m_stackDepth;
1101        } else {
1102            throw new JiBXException("No object on stack");
1103        }
1104    }
1105    
1106    /**
1107     * Get current marshalling object stack depth. This allows tracking
1108     * nested calls to marshal one object while in the process of
1109     * marshalling another object. The bottom item on the stack is always the
1110     * root object being marshalled.
1111     *
1112     * @return number of objects in marshalling stack
1113     */

1114
1115    public int getStackDepth() {
1116        return m_stackDepth;
1117    }
1118    
1119    /**
1120     * Get object from marshalling stack. This stack allows tracking nested
1121     * calls to marshal one object while in the process of marshalling
1122     * another object. The bottom item on the stack is always the root object
1123     * being marshalled.
1124     *
1125     * @param depth object depth in stack to be retrieved (must be in the range
1126     * of zero to the current depth minus one).
1127     * @return object from marshalling stack
1128     */

1129
1130    public Object JavaDoc getStackObject(int depth) {
1131        return m_objectStack[m_stackDepth-depth-1];
1132    }
1133    
1134    /**
1135     * Get top object on marshalling stack. This is safe to call even when no
1136     * objects are on the stack.
1137     *
1138     * @return object from marshalling stack, or <code>null</code> if none
1139     */

1140
1141    public Object JavaDoc getStackTop() {
1142        if (m_stackDepth > 0) {
1143            return m_objectStack[m_stackDepth-1];
1144        } else {
1145            return null;
1146        }
1147    }
1148}
Popular Tags