KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > encoding > SerializationContextImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.encoding;
57
58 import org.jboss.axis.AxisEngine;
59 import org.jboss.axis.Constants;
60 import org.jboss.axis.Handler;
61 import org.jboss.axis.Message;
62 import org.jboss.axis.MessageContext;
63 import org.jboss.axis.attachments.Attachments;
64 import org.jboss.axis.client.Call;
65 import org.jboss.axis.description.OperationDesc;
66 import org.jboss.axis.description.TypeDesc;
67 import org.jboss.axis.encoding.ser.BaseSerializerFactory;
68 import org.jboss.axis.encoding.ser.JAFDataHandlerSerializer;
69 import org.jboss.axis.enums.Use;
70 import org.jboss.axis.handlers.soap.SOAPService;
71 import org.jboss.axis.schema.SchemaVersion;
72 import org.jboss.axis.soap.SOAPConstants;
73 import org.jboss.axis.types.HexBinary;
74 import org.jboss.axis.utils.IDKey;
75 import org.jboss.axis.utils.JavaUtils;
76 import org.jboss.axis.utils.Mapping;
77 import org.jboss.axis.utils.Messages;
78 import org.jboss.axis.utils.NSStack;
79 import org.jboss.axis.utils.XMLUtils;
80 import org.jboss.axis.wsdl.symbolTable.SchemaUtils;
81 import org.jboss.axis.wsdl.symbolTable.SymbolTable;
82 import org.jboss.logging.Logger;
83 import org.w3c.dom.Attr JavaDoc;
84 import org.w3c.dom.CDATASection JavaDoc;
85 import org.w3c.dom.CharacterData JavaDoc;
86 import org.w3c.dom.Comment JavaDoc;
87 import org.w3c.dom.Element JavaDoc;
88 import org.w3c.dom.NamedNodeMap JavaDoc;
89 import org.w3c.dom.Node JavaDoc;
90 import org.w3c.dom.NodeList JavaDoc;
91 import org.w3c.dom.Text JavaDoc;
92 import org.xml.sax.Attributes JavaDoc;
93 import org.xml.sax.helpers.AttributesImpl JavaDoc;
94
95 import javax.xml.namespace.QName JavaDoc;
96 import javax.xml.rpc.JAXRPCException JavaDoc;
97 import javax.xml.rpc.holders.QNameHolder JavaDoc;
98 import javax.xml.soap.SOAPMessage JavaDoc;
99 import java.io.IOException JavaDoc;
100 import java.io.Writer JavaDoc;
101 import java.lang.reflect.Method JavaDoc;
102 import java.util.ArrayList JavaDoc;
103 import java.util.Calendar JavaDoc;
104 import java.util.Date JavaDoc;
105 import java.util.HashMap JavaDoc;
106 import java.util.HashSet JavaDoc;
107 import java.util.Iterator JavaDoc;
108 import java.util.Stack JavaDoc;
109
110 /**
111  * Manage a serialization, including keeping track of namespace mappings
112  * and element stacks.
113  *
114  * @author Glen Daniels (gdaniels@macromedia.com)
115  * @author Rich Scheuerle <scheu@us.ibm.com>
116  */

117 public class SerializationContextImpl implements SerializationContext
118 {
119    private static Logger log = Logger.getLogger(SerializationContextImpl.class.getName());
120
121    private NSStack nsStack = new NSStack();
122    private boolean writingStartTag = false;
123    private boolean onlyXML = true;
124    private int indent = 0;
125    private boolean startOfDocument = true;
126    private Writer JavaDoc writer;
127    private int lastPrefixIndex = 1;
128    private MessageContext msgContext;
129    private QName JavaDoc currentXMLType;
130    // Stack<QName>
131
private Stack elementStack = new Stack();
132
133    /**
134     * The SOAP context we're using
135     */

136    private SOAPConstants soapConstants = SOAPConstants.SOAP11_CONSTANTS;
137
138    private boolean pretty;
139    private static QName JavaDoc multirefQName = new QName JavaDoc("", "multiRef");
140    private static Class JavaDoc[] getSerializerClasses =
141            new Class JavaDoc[]{String JavaDoc.class, Class JavaDoc.class, QName JavaDoc.class};
142
143    /**
144     * Should I write out objects as multi-refs?
145     * <p/>
146     * !!! For now, this is an all-or-nothing flag. Either ALL objects will
147     * be written in-place as hrefs with the full serialization at the end
148     * of the body, or we'll write everything inline (potentially repeating
149     * serializations of identical objects).
150     */

151    private boolean doMultiRefs = false;
152
153    /**
154     * Should I send an XML declaration?
155     */

156    private boolean sendXMLDecl = true;
157
158    /**
159     * Should I send xsi:type attributes?
160     */

161    private boolean sendXSIType = true;
162
163    /**
164     * Should I send minimized elements? As in <element/> instead of
165     * <element></element>.
166     */

167    private boolean sendMinimizedElements = true;
168
169    /**
170     * A place to hold objects we cache for multi-ref serialization, and
171     * remember the IDs we assigned them.
172     */

173    private HashMap JavaDoc multiRefValues = null;
174    private int multiRefIndex = -1;
175
176    private boolean noNamespaceMappings = true;
177
178    // Interop tests with SunOne appserver don't work in document/literal
179
// when the content of the body defines a default namespace
180
// TDI 24-June-2004
181
private boolean noDefaultNamespace;
182
183    class MultiRefItem
184    {
185       String JavaDoc id;
186       QName JavaDoc xmlType;
187       Boolean JavaDoc sendType;
188       Object JavaDoc value;
189
190       MultiRefItem(String JavaDoc id,
191                    QName JavaDoc xmlType,
192                    Boolean JavaDoc sendType, Object JavaDoc value)
193       {
194          this.id = id;
195          this.xmlType = xmlType;
196          this.sendType = sendType;
197          this.value = value;
198       }
199
200    }
201
202    /**
203     * These three variables are necessary to process
204     * multi-level object graphs for multi-ref serialization.
205     * While writing out nested multi-ref objects (via outputMultiRef), we
206     * will fill the secondLevelObjects vector
207     * with any new objects encountered.
208     * The outputMultiRefsFlag indicates whether we are currently within the
209     * outputMultiRef() method (so that serialization() knows to update the
210     * secondLevelObjects vector).
211     * The forceSer variable is the trigger to force actual serialization of the indicated object.
212     */

213    private HashSet JavaDoc secondLevelObjects = null;
214    private Object JavaDoc forceSer = null;
215    private boolean outputMultiRefsFlag = false;
216
217    /**
218     * Which schema version are we using?
219     */

220    SchemaVersion schemaVersion = SchemaVersion.SCHEMA_2001;
221
222    /**
223     * A list of particular namespace -> prefix mappings we should prefer.
224     * See getPrefixForURI() below.
225     */

226    HashMap JavaDoc preferredPrefixes = new HashMap JavaDoc();
227
228    /**
229     * Construct SerializationContextImpl with associated writer
230     *
231     * @param writer java.io.Writer
232     */

233    public SerializationContextImpl(Writer JavaDoc writer)
234    {
235       this.writer = writer;
236       initialize();
237    }
238
239    private void initialize()
240    {
241       // These are the preferred prefixes we'll use instead of the "ns1"
242
// style defaults. MAKE SURE soapConstants IS SET CORRECTLY FIRST!
243
preferredPrefixes.put(soapConstants.getEncodingURI(),
244               Constants.NS_PREFIX_SOAP_ENC);
245       preferredPrefixes.put(Constants.NS_URI_XML,
246               Constants.NS_PREFIX_XML);
247       preferredPrefixes.put(schemaVersion.getXsdURI(),
248               Constants.NS_PREFIX_SCHEMA_XSD);
249       preferredPrefixes.put(schemaVersion.getXsiURI(),
250               Constants.NS_PREFIX_SCHEMA_XSI);
251    }
252
253
254    /**
255     * Construct SerializationContextImpl with associated writer and MessageContext
256     *
257     * @param writer java.io.Writer
258     * @param msgContext is the MessageContext
259     */

260    public SerializationContextImpl(Writer JavaDoc writer, MessageContext msgContext)
261    {
262       this.writer = writer;
263       this.msgContext = msgContext;
264
265       Handler optionSource = null;
266       if (msgContext != null)
267       {
268          soapConstants = msgContext.getSOAPConstants();
269
270          // optionSource = msgContext.getService();
271
if (optionSource == null)
272             optionSource = msgContext.getAxisEngine();
273
274          // Use whatever schema is associated with this MC
275
schemaVersion = msgContext.getSchemaVersion();
276
277          Boolean JavaDoc shouldSendDecl = (Boolean JavaDoc)optionSource.getOption(AxisEngine.PROP_XML_DECL);
278          if (shouldSendDecl != null)
279             sendXMLDecl = shouldSendDecl.booleanValue();
280
281          Boolean JavaDoc shouldSendMultiRefs =
282                  (Boolean JavaDoc)msgContext.getProperty(AxisEngine.PROP_DOMULTIREFS);
283
284          if (shouldSendMultiRefs == null)
285             shouldSendMultiRefs =
286                     (Boolean JavaDoc)optionSource.getOption(AxisEngine.PROP_DOMULTIREFS);
287
288          if (shouldSendMultiRefs != null)
289             doMultiRefs = shouldSendMultiRefs.booleanValue();
290
291          Boolean JavaDoc shouldSendMinimized =
292                  (Boolean JavaDoc)optionSource.getOption(AxisEngine.PROP_SEND_MINIMIZED_ELEMENTS);
293
294          if (shouldSendMinimized != null)
295             sendMinimizedElements = shouldSendMinimized.booleanValue();
296
297          // The SEND_TYPE_ATTR and PROP_SEND_XSI options indicate
298
// whether the elements should have xsi:type attributes.
299
// Only turn this off is the user tells us to
300
if (!msgContext.isPropertyTrue(Call.SEND_TYPE_ATTR, true))
301             sendXSIType = false;
302
303          Boolean JavaDoc opt = (Boolean JavaDoc)optionSource.getOption(AxisEngine.PROP_SEND_XSI);
304          if ((opt != null) && (opt.equals(Boolean.FALSE)))
305          {
306             sendXSIType = false;
307          }
308
309          // A Literal use operation overrides the above settings. Don't
310
// send xsi:type, and don't do multiref in that case.
311
OperationDesc operation = msgContext.getOperation();
312          if (operation != null)
313          {
314             if (operation.getUse() != Use.ENCODED)
315             {
316                sendXSIType = false;
317                doMultiRefs = false;
318             }
319          }
320          else
321          {
322             // A Literal use service overrides the above settings.
323
SOAPService service = msgContext.getService();
324             if (service != null)
325             {
326                if (service.getUse() != Use.ENCODED)
327                {
328                   sendXSIType = false;
329                   doMultiRefs = false;
330                }
331             }
332          }
333       }
334
335       // Set up preferred prefixes based on current schema, soap ver, etc.
336
initialize();
337    }
338
339    /**
340     * Get whether the serialization should be pretty printed.
341     *
342     * @return true/false
343     */

344    public boolean getPretty()
345    {
346       return pretty;
347    }
348
349    /**
350     * Indicate whether the serialization should be pretty printed.
351     *
352     * @param pretty true/false
353     */

354    public void setPretty(boolean pretty)
355    {
356       this.pretty = pretty;
357    }
358
359    /**
360     * Are we doing multirefs?
361     *
362     * @return true or false
363     */

364    public boolean getDoMultiRefs()
365    {
366       return doMultiRefs;
367    }
368
369    /**
370     * Set whether we are doing multirefs
371     */

372    public void setDoMultiRefs(boolean shouldDo)
373    {
374       doMultiRefs = shouldDo;
375    }
376
377    /**
378     * Set whether or not we should write XML declarations.
379     *
380     * @param sendDecl true/false
381     */

382    public void setSendDecl(boolean sendDecl)
383    {
384       sendXMLDecl = sendDecl;
385    }
386
387    /**
388     * Get whether or not to write xsi:type attributes.
389     *
390     * @return true/false
391     */

392    public boolean shouldSendXSIType()
393    {
394       return sendXSIType;
395    }
396
397    /**
398     * Get whether or not to write the default namespace.
399     *
400     * @return true/false
401     */

402    public boolean isNoDefaultNamespace()
403    {
404       return noDefaultNamespace;
405    }
406
407    /**
408     * Set whether or not to write the default namespace.
409     */

410    public void setNoDefaultNamespace(boolean noDefaultNamespace)
411    {
412       this.noDefaultNamespace = noDefaultNamespace;
413    }
414
415    /**
416     * Get the TypeMapping we're using.
417     *
418     * @return TypeMapping or null
419     */

420    public TypeMapping getTypeMapping()
421    {
422       // Always allow the default mappings
423
if (msgContext == null)
424          return DefaultTypeMappingImpl.getSingleton();
425
426       String JavaDoc encodingStyle = msgContext.getEncodingStyle();
427       if (encodingStyle == null)
428          encodingStyle = soapConstants.getEncodingURI();
429       return (TypeMapping)msgContext.
430               getTypeMappingRegistry().getTypeMapping(encodingStyle);
431    }
432
433    /**
434     * Get the TypeMappingRegistry we're using.
435     *
436     * @return TypeMapping or null
437     */

438    public TypeMappingRegistry getTypeMappingRegistry()
439    {
440       if (msgContext == null)
441          return null;
442       return msgContext.getTypeMappingRegistry();
443    }
444
445    /**
446     * Get a prefix for a namespace URI. This method will ALWAYS
447     * return a valid prefix - if the given URI is already mapped in this
448     * serialization, we return the previous prefix. If it is not mapped,
449     * we will add a new mapping and return a generated prefix of the form
450     * "ns<num>".
451     *
452     * @param uri is the namespace uri
453     * @return prefix
454     */

455    public String JavaDoc getPrefixForURI(String JavaDoc uri)
456    {
457       return getPrefixForURI(uri, null, false);
458    }
459
460    /**
461     * Get a prefix for the given namespace URI. If one has already been
462     * defined in this serialization, use that. Otherwise, map the passed
463     * default prefix to the URI, and return that. If a null default prefix
464     * is passed, use one of the form "ns<num>"
465     */

466    public String JavaDoc getPrefixForURI(String JavaDoc uri, String JavaDoc defaultPrefix)
467    {
468       return getPrefixForURI(uri, defaultPrefix, false);
469    }
470
471    /**
472     * Get a prefix for the given namespace URI. If one has already been
473     * defined in this serialization, use that. Otherwise, map the passed
474     * default prefix to the URI, and return that. If a null default prefix
475     * is passed, use one of the form "ns<num>"
476     */

477    public String JavaDoc getPrefixForURI(String JavaDoc uri, String JavaDoc defaultPrefix, boolean attribute)
478    {
479       if ((uri == null) || (uri.length() == 0))
480          return null;
481
482       // If we're looking for an attribute prefix, we shouldn't use the
483
// "" prefix, but always register/find one.
484
String JavaDoc prefix = nsStack.getPrefix(uri, attribute);
485
486       if (prefix == null)
487       {
488          prefix = (String JavaDoc)preferredPrefixes.get(uri);
489
490          if (prefix == null)
491          {
492             if (defaultPrefix == null)
493             {
494                prefix = "ns" + lastPrefixIndex++;
495             }
496             else
497             {
498                prefix = defaultPrefix;
499             }
500          }
501
502          registerPrefixForURI(prefix, uri);
503       }
504
505       return prefix;
506    }
507
508    /**
509     * Register prefix for the indicated uri
510     *
511     * @param prefix
512     * @param uri is the namespace uri
513     */

514    public void registerPrefixForURI(String JavaDoc prefix, String JavaDoc uri)
515    {
516       if (log.isDebugEnabled())
517          log.debug("registerPrefixForURI(" + prefix + ", " + uri + ")");
518
519       // This is a workaround for http://jira.jboss.com/jira/browse/JBWS-64
520
if ("".equals(uri))
521       {
522          log.warn("Ignoring invalid namespace mapping: [prefix=" + prefix + ",uri=" + uri + "]");
523          return;
524       }
525
526       if ((uri != null) && (prefix != null))
527       {
528          if (noNamespaceMappings)
529          {
530             nsStack.push();
531             noNamespaceMappings = false;
532          }
533          nsStack.add(uri, prefix);
534       }
535    }
536
537    /**
538     * Return the current message
539     */

540    public Message getCurrentMessage()
541    {
542       if (msgContext == null)
543          return null;
544       return msgContext.getCurrentMessage();
545    }
546
547    /**
548     * Get the MessageContext we're operating with
549     */

550    public MessageContext getMessageContext()
551    {
552       return msgContext;
553    }
554
555    /**
556     * Convert QName to a string of the form <prefix>:<localpart>
557     *
558     * @param qName
559     * @return prefixed qname representation for serialization.
560     */

561    public String JavaDoc qName2String(QName JavaDoc qName, boolean writeNS)
562    {
563       String JavaDoc prefix = null;
564       String JavaDoc namespaceURI = qName.getNamespaceURI();
565
566       if (namespaceURI.length() == 0)
567       {
568          if (writeNS)
569          {
570             // If this is unqualified (i.e. prefix ""), set the default
571
// namespace to ""
572
String JavaDoc defaultNS = nsStack.getNamespaceURI("");
573             if (defaultNS != null && defaultNS.length() > 0)
574             {
575                registerPrefixForURI("", "");
576             }
577          }
578       }
579       else
580       {
581          prefix = getPrefixForURI(namespaceURI);
582       }
583
584       if ((prefix == null) || (prefix.length() == 0))
585          return qName.getLocalPart();
586
587       StringBuffer JavaDoc sb = new StringBuffer JavaDoc(prefix);
588       sb.append(':');
589       sb.append(qName.getLocalPart());
590       return sb.toString();
591    }
592
593    public String JavaDoc qName2String(QName JavaDoc qName)
594    {
595       return qName2String(qName, false);
596    }
597
598    /**
599     * Convert attribute QName to a string of the form <prefix>:<localpart>
600     * There are slightly different rules for attributes:
601     * - There is no default namespace
602     * - any attribute in a namespace must have a prefix
603     *
604     * @param qName QName
605     * @return prefixed qname representation for serialization.
606     */

607    public String JavaDoc attributeQName2String(QName JavaDoc qName)
608    {
609       String JavaDoc prefix = null;
610
611       if (qName.getNamespaceURI().length() > 0)
612       {
613          prefix = getPrefixForURI(qName.getNamespaceURI(), null, true);
614       }
615
616       if ((prefix == null) || (prefix.length() == 0))
617          return qName.getLocalPart();
618
619       StringBuffer JavaDoc sb = new StringBuffer JavaDoc(prefix);
620       sb.append(':');
621       sb.append(qName.getLocalPart());
622       return sb.toString();
623    }
624
625    /**
626     * Get the QName associated with the specified class.
627     *
628     * @param cls Class of an object requiring serialization.
629     * @return appropriate QName associated with the class.
630     */

631    public QName JavaDoc getQNameForClass(Class JavaDoc cls)
632    {
633       return getTypeMapping().getTypeQName(cls);
634    }
635
636    /**
637     * Indicates whether the object should be interpretted as a primitive
638     * for the purposes of multi-ref processing. A primitive value
639     * is serialized directly instead of using id/href pairs. Thus
640     * primitive serialization/deserialization is slightly faster.
641     *
642     * @param value to be serialized
643     * @return true/false
644     */

645    public boolean isPrimitive(Object JavaDoc value)
646    {
647       if (value == null) return true;
648
649       Class JavaDoc javaType = value.getClass();
650
651       if (javaType.isPrimitive()) return true;
652
653       if (javaType == String JavaDoc.class) return true;
654       if (Calendar JavaDoc.class.isAssignableFrom(javaType)) return true;
655       if (Date JavaDoc.class.isAssignableFrom(javaType)) return true;
656       if (HexBinary.class.isAssignableFrom(javaType)) return true;
657       if (Element JavaDoc.class.isAssignableFrom(javaType)) return true;
658       if (javaType == byte[].class) return true;
659
660       // There has been discussion as to whether arrays themselves should
661
// be regarded as multi-ref.
662
// Here are the three options:
663
// 1) Arrays are full-fledged Objects and therefore should always be
664
// multi-ref'd (Pro: This is like java. Con: Some runtimes don't
665
// support this yet, and it requires more stuff to be passed over the wire.)
666
// 2) Arrays are not full-fledged Objects and therefore should
667
// always be passed as single ref (note the elements of the array
668
// may be multi-ref'd.) (Pro: This seems reasonable, if a user
669
// wants multi-referencing put the array in a container. Also
670
// is more interop compatible. Con: Not like java serialization.)
671
// 3) Arrays of primitives should be single ref, and arrays of
672
// non-primitives should be multi-ref. (Pro: Takes care of the
673
// looping case. Con: Seems like an obtuse rule.)
674
//
675
// Changing the code from (1) to (2) to see if interop fairs better.
676
if (javaType.isArray()) return true;
677
678       // Note that java.lang wrapper classes (i.e. java.lang.Integer) are
679
// not primitives unless the corresponding type is an xsd type.
680
// (If the wrapper maps to a soap encoded primitive, it can be nillable
681
// and multi-ref'd).
682
QName JavaDoc qName = getQNameForClass(javaType);
683       if (qName != null && Constants.isSchemaXSD(qName.getNamespaceURI()))
684       {
685          if (SchemaUtils.isSimpleSchemaType(qName))
686          {
687             return true;
688          }
689       }
690
691       return false;
692    }
693
694    /**
695     * Serialize the indicated value as an element with the name
696     * indicated by elemQName.
697     * The attributes are additional attribute to be serialized on the element.
698     * The value is the object being serialized. (It may be serialized
699     * directly or serialized as an mult-ref'd item)
700     * The value is an Object, which may be a wrapped primitive, the
701     * javaType is the actual unwrapped object type.
702     * The xmlType (if specified) is the QName of the type that is used to set
703     * xsi:type. If not specified, xsi:type is set by using the javaType to
704     * find an appopriate xmlType from the TypeMappingRegistry.
705     * The sendNull flag indicates whether null values should be sent over the
706     * wire (default is to send such values with xsi:nil="true").
707     * The sendType flag indicates whether the xsi:type flag should be sent
708     * (default is true).
709     *
710     * @param elemQName is the QName of the element
711     * @param attributes are additional attributes
712     * @param value is the object to serialize
713     */

714    public void serialize(QName JavaDoc elemQName,
715                          Attributes JavaDoc attributes,
716                          Object JavaDoc value)
717            throws IOException JavaDoc
718    {
719       serialize(elemQName, attributes, value, null, true, null);
720    }
721
722    /**
723     * Serialize the indicated value as an element with the name
724     * indicated by elemQName.
725     * The attributes are additional attribute to be serialized on the element.
726     * The value is the object being serialized. (It may be serialized
727     * directly or serialized as an mult-ref'd item)
728     * The value is an Object, which may be a wrapped primitive.
729     * The xmlType (if specified) is the QName of the type that is used to set
730     * xsi:type.
731     * The sendNull flag indicates whether null values should be sent over the
732     * wire (default is to send such values with xsi:nil="true").
733     * The sendType flag indicates whether the xsi:type flag should be sent
734     * (default is true).
735     *
736     * @param elemQName is the QName of the element
737     * @param attributes are additional attributes
738     * @param value is the object to serialize
739     * @param xmlType is the qname of the type or null.
740     * @param sendNull determines whether to send null values.
741     * @param sendType determines whether to set xsi:type attribute.
742     */

743    public void serialize(QName JavaDoc elemQName,
744                          Attributes JavaDoc attributes,
745                          Object JavaDoc value,
746                          QName JavaDoc xmlType,
747                          boolean sendNull,
748                          Boolean JavaDoc sendType)
749            throws IOException JavaDoc
750    {
751       boolean shouldSendType = (sendType == null) ? shouldSendXSIType() :
752               sendType.booleanValue();
753
754       if (value == null)
755       {
756          // If the value is null, the element is
757
// passed with xsi:nil="true" to indicate that no object is present.
758
if (sendNull)
759          {
760             AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
761             if (attributes != null && 0 < attributes.getLength())
762                attrs.setAttributes(attributes);
763             if (shouldSendType)
764                attrs = (AttributesImpl JavaDoc)setTypeAttribute(attrs, xmlType);
765             String JavaDoc nil = schemaVersion.getNilQName().getLocalPart();
766             attrs.addAttribute(schemaVersion.getXsiURI(), nil, "xsi:" + nil,
767                     "CDATA", "1");
768             startElement(elemQName, attrs);
769             endElement();
770          }
771          return;
772       }
773
774       Message msg = getCurrentMessage();
775       if (null != msg)
776       {
777          //Get attachments. returns null if no attachment support.
778
Attachments attachments = msg.getAttachmentsImpl();
779
780          if (null != attachments)
781          {
782             // Attachment support
783
if (attachments.isAttachment(value) || getSerializer(value.getClass(), xmlType, null) instanceof JAFDataHandlerSerializer)
784             {
785                // This is an object that should be treated as an attachment, so allow the
786
// attachment to do its own serialization
787
serializeActual(elemQName, attributes, value, xmlType, sendType);
788
789                // No need to add to mulitRefs.
790
// Attachment data stream handled by the message
791
return;
792             }
793          }
794       }
795
796       // If multi-reference is enabled and this object value is not a primitive
797
// and we are not forcing serialization of the object, then generate
798
// an element href (and store the object for subsequent outputMultiRef
799
// processing).
800

801       // NOTE : you'll notice that everywhere we register objects in the
802
// multiRefValues and secondLevelObjects collections, we key them
803
// using getIdentityKey(value) instead of the Object reference itself.
804
// THIS IS IMPORTANT, and please make sure you understand what's
805
// going on if you change any of this code. It's this way to make
806
// sure that individual Objects are serialized separately even if the
807
// hashCode() and equals() methods have been overloaded to make two
808
// Objects appear equal.
809

810       if (doMultiRefs && (msgContext == null || msgContext.isEncoded()) &&
811               (value != forceSer) && !isPrimitive(value))
812       {
813          if (multiRefIndex == -1)
814             multiRefValues = new HashMap JavaDoc();
815
816          String JavaDoc id;
817
818          // Look for a multi-ref descriptor for this Object.
819
MultiRefItem mri = (MultiRefItem)multiRefValues.get(getIdentityKey(value));
820          if (mri == null)
821          {
822             // Didn't find one, so create one, give it a new ID, and store
823
// it for next time.
824
multiRefIndex++;
825             id = "id" + multiRefIndex;
826             mri = new MultiRefItem(id, xmlType, sendType, value);
827             multiRefValues.put(getIdentityKey(value), mri);
828
829             /**
830              * If we're SOAP 1.2, we can "inline" the serializations,
831              * so put it out now, with it's ID.
832              */

833             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
834             {
835                AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
836                if (attributes != null && 0 < attributes.getLength())
837                   attrs.setAttributes(attributes);
838                attrs.addAttribute("", Constants.ATTR_ID, "id", "CDATA",
839                        id);
840                serializeActual(elemQName, attrs, value, xmlType, sendType);
841                return;
842             }
843
844
845             /** If we're in the middle of writing out
846              * the multi-refs, we've already cloned the list of objects
847              * and so even though we add a new one to multiRefValues,
848              * it won't get serialized this time around.
849              *
850              * To deal with this, we maintain a list of "second level"
851              * Objects - ones that need serializing as a result of
852              * serializing the first level. When outputMultiRefs() is
853              * nearly finished, it checks to see if secondLevelObjects
854              * is empty, and if not, it goes back and loops over those
855              * Objects. This can happen N times depending on how deep
856              * the Object graph goes.
857              */

858             if (outputMultiRefsFlag)
859             {
860                if (secondLevelObjects == null)
861                   secondLevelObjects = new HashSet JavaDoc();
862                secondLevelObjects.add(getIdentityKey(value));
863             }
864          }
865          else
866          {
867             // Found one, remember it's ID
868
id = mri.id;
869          }
870
871          // Serialize an HREF to our object
872
AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
873          if (attributes != null && 0 < attributes.getLength())
874             attrs.setAttributes(attributes);
875          attrs.addAttribute("", soapConstants.getAttrHref(), soapConstants.getAttrHref(),
876                  "CDATA", '#' + id);
877
878          startElement(elemQName, attrs);
879          endElement();
880          return;
881       }
882
883       // The forceSer variable is set by outputMultiRefs to force
884
// serialization of this object via the serialize(...) call
885
// below. However, if the forced object contains a self-reference, we
886
// get into an infinite loop..which is why it is set back to null
887
// before the actual serialization.
888
if (value == forceSer)
889          forceSer = null;
890
891       // Actually serialize the value. (i.e. not an href like above)
892
serializeActual(elemQName, attributes, value, xmlType, sendType);
893    }
894
895    /**
896     * Get an IDKey that represents the unique identity of the object.
897     * This is used as a unique key into a HashMap which will
898     * not give false hits on other Objects where hashCode() and equals()
899     * have been overriden to match.
900     *
901     * @param value the Object to hash
902     * @return a unique IDKey for the identity
903     */

904    private IDKey getIdentityKey(Object JavaDoc value)
905    {
906       return new IDKey(value);
907    }
908
909    /**
910     * The serialize method uses hrefs to reference all non-primitive
911     * values. These values are stored and serialized by calling
912     * outputMultiRefs after the serialize method completes.
913     */

914    public void outputMultiRefs() throws IOException JavaDoc
915    {
916       if (!doMultiRefs || (multiRefValues == null) ||
917               soapConstants == SOAPConstants.SOAP12_CONSTANTS)
918          return;
919       outputMultiRefsFlag = true;
920       AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
921       attrs.addAttribute("", "", "", "", "");
922
923       String JavaDoc encodingURI = soapConstants.getEncodingURI();
924       // explicitly state that this attribute is not a root
925
String JavaDoc prefix = getPrefixForURI(encodingURI);
926       String JavaDoc root = prefix + ":root";
927       attrs.addAttribute(encodingURI, Constants.ATTR_ROOT, root,
928               "CDATA", "0");
929
930       // Make sure we put the encodingStyle on each multiref element we output.
931
addEncodingStyleAttribute(attrs);
932
933       // Make a copy of the keySet because it could be updated
934
// during processing
935
HashSet JavaDoc keys = new HashSet JavaDoc();
936       keys.addAll(multiRefValues.keySet());
937       Iterator JavaDoc i = keys.iterator();
938       while (i.hasNext())
939       {
940          while (i.hasNext())
941          {
942             Object JavaDoc val = i.next();
943             MultiRefItem mri = (MultiRefItem)multiRefValues.get(val);
944             attrs.setAttribute(0, "", Constants.ATTR_ID, "id", "CDATA",
945                     mri.id);
946
947             forceSer = mri.value;
948
949             // Now serialize the value.
950
// The sendType parameter is defaulted for interop purposes.
951
// Some of the remote services do not know how to
952
// ascertain the type in these circumstances (though Axis does).
953
serialize(multirefQName, attrs, mri.value,
954                     mri.xmlType,
955                     true,
956                     Boolean.TRUE); // mri.sendType
957
}
958
959          // Done processing the iterated values. During the serialization
960
// of the values, we may have run into new nested values. These
961
// were placed in the secondLevelObjects map, which we will now
962
// process by changing the iterator to locate these values.
963
if (secondLevelObjects != null)
964          {
965             i = secondLevelObjects.iterator();
966             secondLevelObjects = null;
967          }
968       }
969
970       // Reset maps and flags
971
forceSer = null;
972       outputMultiRefsFlag = false;
973       multiRefValues = null;
974       multiRefIndex = -1;
975       secondLevelObjects = null;
976    }
977
978    /** Add the encoding style as an attribute
979     * According to the BP-1.0/4.1.7 we should not do that but the s1as interop tests fail otherwise
980     * [TDI 11-Sep-2004]
981     */

982    private void addEncodingStyleAttribute(AttributesImpl JavaDoc attrs)
983    {
984       String JavaDoc encodingStyle;
985
986       if (msgContext != null)
987       {
988          encodingStyle = msgContext.getEncodingStyle();
989       }
990       else
991       {
992          encodingStyle = soapConstants.getEncodingURI();
993       }
994
995       String JavaDoc encStyle = getPrefixForURI(soapConstants.getEnvelopeURI()) + ':' + Constants.ATTR_ENCODING_STYLE;
996       attrs.addAttribute(soapConstants.getEnvelopeURI(), Constants.ATTR_ENCODING_STYLE, encStyle, "CDATA", encodingStyle);
997    }
998
999    public void startDocument() throws IOException JavaDoc
1000   {
1001      if (startOfDocument && sendXMLDecl)
1002      {
1003         writer.write("<?xml version=\"1.0\" encoding=\"");
1004         // The origional logic is very simple
1005
// writer.write(XMLUtils.getEncoding());
1006
// The following logic is devised to utilize CHARACTER_SET_ENCODING property from SAAJ 1.2.
1007
String JavaDoc encoding = null;
1008         if (msgContext != null)
1009         {
1010            encoding = (String JavaDoc)msgContext.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
1011         }
1012         if (encoding == null)
1013         {
1014            encoding = XMLUtils.getEncoding();
1015         }
1016         writer.write(encoding);
1017         writer.write("\"?>\n");
1018         startOfDocument = false;
1019      }
1020   }
1021
1022   public void endDocument() throws IOException JavaDoc
1023   {
1024   }
1025
1026   /**
1027    * Writes (using the Writer) the start tag for element QName along with the
1028    * indicated attributes and namespace mappings.
1029    *
1030    * @param qName is the name of the element
1031    * @param attributes are the attributes to write
1032    */

1033   public void startElement(QName JavaDoc qName, Attributes JavaDoc attributes)
1034           throws IOException JavaDoc
1035   {
1036      ArrayList JavaDoc vecQNames = new ArrayList JavaDoc();
1037      if (log.isDebugEnabled())
1038      {
1039         log.debug(Messages.getMessage("startElem00",
1040                 "[" + qName.getNamespaceURI() + "]:" + qName.getLocalPart()));
1041      }
1042
1043      if (writingStartTag)
1044      {
1045         writer.write('>');
1046         if (pretty) writer.write(JavaUtils.LS);
1047         indent++;
1048      }
1049
1050      if (pretty) for (int i = 0; i < indent; i++) writer.write(' ');
1051      String JavaDoc elementQName = qName2String(qName, true);
1052      writer.write('<');
1053
1054      writer.write(elementQName);
1055
1056      if (attributes != null)
1057      {
1058         for (int i = 0; i < attributes.getLength(); i++)
1059         {
1060            String JavaDoc qname = attributes.getQName(i);
1061            writer.write(' ');
1062
1063            String JavaDoc prefix = "";
1064            String JavaDoc uri = attributes.getURI(i);
1065            if (uri != null && uri.length() > 0)
1066            {
1067               if (qname.length() == 0)
1068               {
1069                  // If qname isn't set, generate one
1070
prefix = getPrefixForURI(uri);
1071               }
1072               else
1073               {
1074                  // If it is, make sure the prefix looks reasonable.
1075
int idx = qname.indexOf(':');
1076                  if (idx > -1)
1077                  {
1078                     prefix = qname.substring(0, idx);
1079                     prefix = getPrefixForURI(uri, prefix, true);
1080                  }
1081
1082                  if (uri.equals(Constants.NS_URI_XMLNS))
1083                  {
1084                     prefix = "xmlns";
1085                  }
1086               }
1087
1088               if (prefix.length() > 0)
1089               {
1090                  qname = prefix + ':' + attributes.getLocalName(i);
1091               }
1092               else
1093               {
1094                  qname = attributes.getLocalName(i);
1095               }
1096            }
1097            else
1098            {
1099               qname = attributes.getQName(i);
1100               if (qname.length() == 0)
1101                  qname = attributes.getLocalName(i);
1102            }
1103
1104            if (qname.startsWith("xmlns"))
1105            {
1106               vecQNames.add(qname);
1107            }
1108            writer.write(qname);
1109            writer.write("=\"");
1110            writer.write(XMLUtils.xmlEncodeString(attributes.getValue(i)));
1111            writer.write('"');
1112         }
1113      }
1114
1115      if (noNamespaceMappings)
1116      {
1117         nsStack.push();
1118      }
1119      else
1120      {
1121         for (Mapping map = nsStack.topOfFrame(); map != null; map = nsStack.next())
1122         {
1123            StringBuffer JavaDoc sb = new StringBuffer JavaDoc("xmlns");
1124            boolean isDefaultNS = map.getPrefix().equals("");
1125            if (!isDefaultNS || !isNoDefaultNamespace())
1126            {
1127               if (!isDefaultNS)
1128               {
1129                  sb.append(':');
1130                  sb.append(map.getPrefix());
1131               }
1132
1133               if (vecQNames.indexOf(sb.toString()) == -1)
1134               {
1135                  writer.write(' ');
1136                  sb.append("=\"");
1137                  sb.append(map.getNamespaceURI());
1138                  sb.append('"');
1139                  writer.write(sb.toString());
1140               }
1141            }
1142         }
1143
1144         noNamespaceMappings = true;
1145      }
1146
1147      writingStartTag = true;
1148
1149      elementStack.push(qName);
1150
1151      onlyXML = true;
1152   }
1153
1154   /**
1155    * Writes the end element tag for the open element.
1156    */

1157   public void endElement()
1158           throws IOException JavaDoc
1159   {
1160      QName JavaDoc qname = (QName JavaDoc)elementStack.pop();
1161      String JavaDoc elementQName = qName2String(qname, true);
1162
1163      if (log.isDebugEnabled())
1164      {
1165         log.debug(Messages.getMessage("endElem00", "" + elementQName));
1166      }
1167
1168      nsStack.pop();
1169
1170      if (writingStartTag)
1171      {
1172         if (sendMinimizedElements)
1173         {
1174            writer.write("/>");
1175         }
1176         else
1177         {
1178            writer.write("></");
1179            writer.write(elementQName);
1180            writer.write('>');
1181         }
1182         if (pretty) writer.write(JavaUtils.LS);
1183         writingStartTag = false;
1184         return;
1185      }
1186
1187      if (onlyXML)
1188      {
1189         indent--;
1190         if (pretty) for (int i = 0; i < indent; i++) writer.write(' ');
1191      }
1192      writer.write("</");
1193      writer.write(elementQName);
1194      writer.write('>');
1195      if (pretty) if (indent > 0) writer.write(JavaUtils.LS);
1196      onlyXML = true;
1197   }
1198
1199   /**
1200    * Convenience operation to write out (to Writer) the characters
1201    * in p1 starting at index p2 for length p3.
1202    *
1203    * @param p1 character array to write
1204    * @param p2 starting index in array
1205    * @param p3 length to write
1206    */

1207   public void writeChars(char[] p1, int p2, int p3)
1208           throws IOException JavaDoc
1209   {
1210      if (writingStartTag)
1211      {
1212         writer.write('>');
1213         writingStartTag = false;
1214      }
1215      writeSafeString(String.valueOf(p1, p2, p3));
1216      onlyXML = false;
1217   }
1218
1219   /**
1220    * Convenience operation to write out (to Writer) the String
1221    *
1222    * @param string is the String to write.
1223    */

1224   public void writeString(String JavaDoc string)
1225           throws IOException JavaDoc
1226   {
1227      if (writingStartTag)
1228      {
1229         writer.write('>');
1230         writingStartTag = false;
1231      }
1232      writer.write(string);
1233      onlyXML = false;
1234   }
1235
1236   /**
1237    * Convenience operation to write out (to Writer) the String
1238    * properly encoded with xml entities (like &amp)
1239    *
1240    * @param string is the String to write.
1241    */

1242   public void writeSafeString(String JavaDoc string)
1243           throws IOException JavaDoc
1244   {
1245      writeString(XMLUtils.xmlEncodeString(string));
1246   }
1247
1248   /**
1249    * Output a DOM representation to a SerializationContext
1250    *
1251    * @param el is a DOM Element
1252    */

1253   public void writeDOMElement(Element JavaDoc el)
1254           throws IOException JavaDoc
1255   {
1256      AttributesImpl JavaDoc attributes = null;
1257      NamedNodeMap JavaDoc attrMap = el.getAttributes();
1258
1259      if (attrMap.getLength() > 0)
1260      {
1261         attributes = new AttributesImpl JavaDoc();
1262         for (int i = 0; i < attrMap.getLength(); i++)
1263         {
1264            Attr JavaDoc attr = (Attr JavaDoc)attrMap.item(i);
1265            String JavaDoc tmp = attr.getNamespaceURI();
1266            if (tmp != null && tmp.equals(Constants.NS_URI_XMLNS))
1267            {
1268               String JavaDoc prefix = attr.getLocalName();
1269               if (prefix != null)
1270               {
1271                  if (prefix.equals("xmlns"))
1272                     prefix = "";
1273                  String JavaDoc nsURI = attr.getValue();
1274                  registerPrefixForURI(prefix, nsURI);
1275               }
1276               continue;
1277            }
1278
1279            attributes.addAttribute(attr.getNamespaceURI(),
1280                    attr.getLocalName(),
1281                    attr.getName(),
1282                    "CDATA", attr.getValue());
1283         }
1284      }
1285
1286      String JavaDoc namespaceURI = el.getNamespaceURI();
1287      String JavaDoc localPart = el.getLocalName();
1288      if (localPart == null)
1289         localPart = el.getNodeName();
1290
1291      QName JavaDoc qName = new QName JavaDoc(namespaceURI, localPart);
1292
1293      startElement(qName, attributes);
1294
1295      NodeList JavaDoc children = el.getChildNodes();
1296      for (int i = 0; i < children.getLength(); i++)
1297      {
1298         Node JavaDoc child = children.item(i);
1299         if (child instanceof Element JavaDoc)
1300         {
1301            writeDOMElement((Element JavaDoc)child);
1302         }
1303         else if (child instanceof CDATASection JavaDoc)
1304         {
1305            writeString("<![CDATA[");
1306            writeString(((Text JavaDoc)child).getData());
1307            writeString("]]>");
1308         }
1309         else if (child instanceof Comment JavaDoc)
1310         {
1311            writeString("<!--");
1312            writeString(((CharacterData JavaDoc)child).getData());
1313            writeString("-->");
1314         }
1315         else if (child instanceof Text JavaDoc)
1316         {
1317            writeSafeString(((Text JavaDoc)child).getData());
1318         }
1319      }
1320
1321      endElement();
1322   }
1323
1324   /**
1325    * Convenience method to get the Serializer for a specific
1326    * java type
1327    *
1328    * @param javaType is Class for a type to serialize
1329    * @return Serializer
1330    */

1331   public final Serializer getSerializerForJavaType(Class JavaDoc javaType)
1332   {
1333      SerializerFactory serF = null;
1334      Serializer ser = null;
1335      try
1336      {
1337         serF = (SerializerFactory)getTypeMapping().getSerializer(javaType);
1338         if (serF != null)
1339         {
1340            ser = (Serializer)serF.getSerializerAs(Constants.AXIS_SAX);
1341         }
1342      }
1343      catch (JAXRPCException JavaDoc e)
1344      {
1345      }
1346
1347      return ser;
1348   }
1349
1350   /**
1351    * Obtains the type attribute that should be serialized and returns the new list of Attributes
1352    *
1353    * @param attributes of the qname
1354    * @param type is the qname of the type
1355    * @return new list of Attributes
1356    */

1357   public Attributes JavaDoc setTypeAttribute(Attributes JavaDoc attributes, QName JavaDoc type)
1358   {
1359      if (type == null ||
1360              type.getLocalPart().indexOf(SymbolTable.ANON_TOKEN) >= 0 ||
1361              ((attributes != null) &&
1362              (attributes.getIndex(Constants.URI_DEFAULT_SCHEMA_XSI,
1363                      "type") != -1)))
1364         return attributes;
1365
1366      AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
1367      if (attributes != null && 0 < attributes.getLength())
1368         attrs.setAttributes(attributes);
1369
1370      String JavaDoc prefix = getPrefixForURI(Constants.URI_DEFAULT_SCHEMA_XSI,
1371              "xsi");
1372
1373      attrs.addAttribute(Constants.URI_DEFAULT_SCHEMA_XSI,
1374              "type",
1375              prefix + ":type",
1376              "CDATA", attributeQName2String(type));
1377      return attrs;
1378   }
1379
1380   /**
1381    * Invoked to do the actual serialization of the qName (called by serialize above).
1382    * additional attributes that will be serialized with the qName.
1383    *
1384    * @param elemQName is the QName of the element
1385    * @param attributes are additional attributes
1386    * @param value is the object to serialize
1387    * @param xmlType (optional) is the desired type QName.
1388    * @param sendType indicates whether the xsi:type attribute should be set.
1389    */

1390   private void serializeActual(QName JavaDoc elemQName,
1391                                Attributes JavaDoc attributes,
1392                                Object JavaDoc value,
1393                                QName JavaDoc xmlType,
1394                                Boolean JavaDoc sendType)
1395           throws IOException JavaDoc
1396   {
1397      boolean shouldSendType = (sendType == null) ? shouldSendXSIType() :
1398              sendType.booleanValue();
1399
1400      if (value != null)
1401      {
1402         Class JavaDoc javaType = value.getClass();
1403         TypeMapping tm = getTypeMapping();
1404
1405         if (tm == null)
1406         {
1407            throw new IOException JavaDoc(Messages.getMessage("noSerializer00",
1408                    value.getClass().getName(),
1409                    "" + this));
1410         }
1411
1412         // Set currentXMLType to the one desired one.
1413
// Note for maxOccurs usage this xmlType is the
1414
// type of the component not the type of the array.
1415
currentXMLType = xmlType;
1416
1417         // if we're looking for xsd:anyType, accept anything...
1418
if (Constants.equals(Constants.XSD_ANYTYPE, xmlType))
1419         {
1420            xmlType = null;
1421            shouldSendType = true;
1422         }
1423
1424         // Try getting a serializer for the prefered xmlType
1425
QNameHolder JavaDoc actualXMLType = new QNameHolder JavaDoc();
1426         Serializer ser = getSerializer(javaType, xmlType, actualXMLType);
1427
1428         if (ser != null)
1429         {
1430            // Send the xmlType if indicated or if
1431
// the actual xmlType is different than the
1432
// prefered xmlType
1433
if (shouldSendType || (xmlType != null && !xmlType.equals(actualXMLType.value)))
1434            {
1435               // Only do this if we are encoded
1436
// TDI 21-June-2004
1437
if (msgContext != null && msgContext.isEncoded())
1438                  attributes = setTypeAttribute(attributes, actualXMLType.value);
1439            }
1440
1441            // -----------------
1442
// NOTE: I have seen doc/lit tests that use
1443
// the type name as the element name in multi-ref cases
1444
// (for example <soapenc:Array ... >)
1445
// In such cases the xsi:type is not passed along.
1446
// -----------------
1447
// The multiref QName is our own fake name.
1448
// It may be beneficial to set the name to the
1449
// type name, but I didn't see any improvements
1450
// in the interop tests.
1451
//if (name.equals(multirefQName) && type != null)
1452
// name = type;
1453
ser.serialize(elemQName, attributes, value, this);
1454            return;
1455         }
1456
1457         // if no serializer was configured try to find one dynamically using WSDLJava
1458
// generated metadata
1459
try
1460         {
1461            Method JavaDoc method = value.getClass().getMethod("getSerializer", getSerializerClasses);
1462            if (method != null)
1463            {
1464               Serializer serializer = (Serializer)method.invoke(value,
1465                       new Object JavaDoc[]{"", value.getClass(), elemQName});
1466               TypeDesc typedesc = TypeDesc.getTypeDescForClass(value.getClass());
1467               if (typedesc != null)
1468               {
1469                  QName JavaDoc qname = typedesc.getXmlType();
1470                  if (qname != null)
1471                  {
1472                     attributes = setTypeAttribute(attributes,
1473                             qname);
1474                  }
1475               }
1476               serializer.serialize(elemQName, attributes, value, this);
1477               return;
1478            }
1479         }
1480         catch (Exception JavaDoc e)
1481         {
1482         }
1483
1484         throw new IOException JavaDoc(Messages.getMessage("noSerializer00",
1485                 value.getClass().getName(), "" + tm));
1486      }
1487      // !!! Write out a generic null, or get type info from somewhere else?
1488
}
1489
1490   /**
1491    * Get the currently prefered xmlType
1492    *
1493    * @return QName of xmlType or null
1494    */

1495   public QName JavaDoc getCurrentXMLType()
1496   {
1497      return currentXMLType;
1498   }
1499
1500   /**
1501    * Walk the interfaces of a class looking for a serializer for that
1502    * interface. Include any parent interfaces in the search also.
1503    */

1504   private SerializerFactory getSerializerFactoryFromInterface(Class JavaDoc javaType,
1505                                                               QName JavaDoc xmlType,
1506                                                               TypeMapping tm)
1507   {
1508      SerializerFactory serFactory = null;
1509      Class JavaDoc[] interfaces = javaType.getInterfaces();
1510      if (interfaces != null)
1511      {
1512         for (int i = 0; i < interfaces.length; i++)
1513         {
1514            Class JavaDoc iface = interfaces[i];
1515            serFactory = (SerializerFactory)tm.getSerializer(iface,
1516                    xmlType);
1517            if (serFactory == null)
1518               serFactory = getSerializerFactoryFromInterface(iface, xmlType, tm);
1519            if (serFactory != null)
1520               break;
1521
1522         }
1523      }
1524      return serFactory;
1525   }
1526
1527   /**
1528    * getSerializer
1529    * Attempts to get a serializer for the indicated javaType and xmlType.
1530    *
1531    * @param javaType is the type of the object
1532    * @param xmlType is the preferred qname type.
1533    * @param actualXMLType is set to a QNameHolder or null.
1534    * If a QNameHolder, the actual xmlType is returned.
1535    * @return found class/serializer or null
1536    */

1537   private Serializer getSerializer(Class JavaDoc javaType, QName JavaDoc xmlType, QNameHolder JavaDoc actualXMLType)
1538   {
1539
1540      log.debug("Enter:getSerializer: [class=" + javaType + ",xmlType=" + xmlType + "]");
1541
1542      SerializerFactory serFactory = null;
1543      TypeMapping tm = getTypeMapping();
1544      if (actualXMLType != null)
1545      {
1546         actualXMLType.value = null;
1547      }
1548
1549      while (javaType != null)
1550      {
1551         serFactory = (SerializerFactory)tm.getSerializer(javaType, xmlType);
1552         if (serFactory != null)
1553            break;
1554
1555         // Walk my interfaces...
1556
serFactory = getSerializerFactoryFromInterface(javaType, xmlType, tm);
1557
1558         // Finally, head to my superclass
1559
if (serFactory != null)
1560            break;
1561
1562         javaType = javaType.getSuperclass();
1563      }
1564
1565      // Using the serialization factory, create a serializer
1566
Serializer ser = null;
1567      if (serFactory != null)
1568      {
1569         ser = (Serializer)serFactory.getSerializerAs(Constants.AXIS_SAX);
1570
1571         if (actualXMLType != null)
1572         {
1573            // Get the actual qname xmlType from the factory.
1574
// If not found via the factory, fall back to a less
1575
// performant solution.
1576
if (serFactory instanceof BaseSerializerFactory)
1577            {
1578               actualXMLType.value =
1579                       ((BaseSerializerFactory)serFactory).getXMLType();
1580            }
1581            if (actualXMLType.value == null)
1582            {
1583               actualXMLType.value =
1584                       ((TypeMappingImpl)tm).getXMLType(javaType,
1585                               xmlType);
1586            }
1587         }
1588      }
1589
1590      log.debug("Exit:getSerializer: " + ser);
1591
1592      return ser;
1593   }
1594
1595   public String JavaDoc getValueAsString(Object JavaDoc value, QName JavaDoc xmlType) throws IOException JavaDoc
1596   {
1597      Serializer ser = getSerializer(value.getClass(), xmlType, null);
1598      if (!(ser instanceof SimpleValueSerializer))
1599      {
1600         throw new IOException JavaDoc(Messages.getMessage("needSimpleValueSer",
1601                 ser.getClass().getName()));
1602      }
1603      SimpleValueSerializer simpleSer = (SimpleValueSerializer)ser;
1604      return simpleSer.getValueAsString(value, this);
1605   }
1606
1607   /** Get the stack of element qnames.
1608    */

1609   public Stack getElementStack()
1610   {
1611      return elementStack;
1612   }
1613}
1614
Popular Tags