KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2002 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 package org.jboss.axis.encoding;
56
57 import org.jboss.axis.AxisFault;
58 import org.jboss.axis.Constants;
59 import org.jboss.axis.Message;
60 import org.jboss.axis.MessageContext;
61 import org.jboss.axis.attachments.Attachments;
62 import org.jboss.axis.description.TypeDesc;
63 import org.jboss.axis.message.EnvelopeBuilder;
64 import org.jboss.axis.message.EnvelopeHandler;
65 import org.jboss.axis.message.IDResolver;
66 import org.jboss.axis.message.NullAttributes;
67 import org.jboss.axis.message.SAX2EventRecorder;
68 import org.jboss.axis.message.SOAPElementAxisImpl;
69 import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
70 import org.jboss.axis.message.SOAPHandler;
71 import org.jboss.axis.schema.SchemaVersion;
72 import org.jboss.axis.soap.SOAPConstants;
73 import org.jboss.axis.utils.JavaUtils;
74 import org.jboss.axis.utils.Messages;
75 import org.jboss.axis.utils.NSStack;
76 import org.jboss.axis.utils.XMLUtils;
77 import org.jboss.logging.Logger;
78 import org.xml.sax.Attributes JavaDoc;
79 import org.xml.sax.InputSource JavaDoc;
80 import org.xml.sax.Locator JavaDoc;
81 import org.xml.sax.SAXException JavaDoc;
82 import org.xml.sax.ext.LexicalHandler JavaDoc;
83 import org.xml.sax.helpers.AttributesImpl JavaDoc;
84 import org.xml.sax.helpers.DefaultHandler JavaDoc;
85
86 import javax.xml.namespace.QName JavaDoc;
87 import javax.xml.parsers.SAXParser JavaDoc;
88 import javax.xml.rpc.JAXRPCException JavaDoc;
89 import javax.xml.rpc.holders.Holder JavaDoc;
90 import javax.xml.soap.SOAPException JavaDoc;
91 import java.io.IOException JavaDoc;
92 import java.lang.reflect.Method JavaDoc;
93 import java.util.ArrayList JavaDoc;
94 import java.util.HashMap JavaDoc;
95
96 /**
97  * @author Glen Daniels (gdaniels@macromedia.com)
98  * Re-architected for JAX-RPC Compliance by:
99  * @author Rich Scheuerle (scheu@us.ibm.com)
100  */

101
102 public class DeserializationContextImpl extends DefaultHandler JavaDoc implements LexicalHandler JavaDoc, DeserializationContext
103 {
104    private static Logger log = Logger.getLogger(DeserializationContextImpl.class.getName());
105
106    static final SchemaVersion schemaVersions[] = new SchemaVersion[]{
107       SchemaVersion.SCHEMA_1999,
108       SchemaVersion.SCHEMA_2000,
109       SchemaVersion.SCHEMA_2001,
110    };
111
112    private NSStack namespaces = new NSStack();
113
114    private Locator JavaDoc locator;
115
116    // for performance reasons, keep the top of the stack separate from
117
// the remainder of the handlers, and therefore readily available.
118
private SOAPHandler topHandler = null;
119    private ArrayList JavaDoc pushedDownHandlers = new ArrayList JavaDoc();
120
121    //private SAX2EventRecorder recorder = new SAX2EventRecorder();
122
private SAX2EventRecorder recorder = null;
123    private SOAPEnvelopeAxisImpl envelope;
124
125    /* A map of IDs -> IDResolvers */
126    private HashMap JavaDoc idMap;
127    private LocalIDResolver localIDs;
128
129    private HashMap JavaDoc fixups;
130
131    static final SOAPHandler nullHandler = new SOAPHandler();
132
133    protected MessageContext msgContext;
134
135    private boolean doneParsing;
136    protected InputSource JavaDoc inputSource;
137
138    private SOAPElementAxisImpl curElement;
139    private StringBuffer JavaDoc curElementContent;
140
141    protected int startOfMappingsPos = -1;
142
143    // This is a hack to associate the first schema namespace we see with
144
// the correct SchemaVersion. It assumes people won't often be mixing
145
// schema versions in a given document, which I think is OK. --Glen
146
protected boolean haveSeenSchemaNS = false;
147
148    private static final Class JavaDoc[] DESERIALIZER_CLASSES =
149            new Class JavaDoc[]{String JavaDoc.class, Class JavaDoc.class, QName JavaDoc.class};
150    private static final String JavaDoc DESERIALIZER_METHOD = "getDeserializer";
151
152    public void deserializing(boolean isDeserializing)
153    {
154       doneParsing = isDeserializing;
155    }
156
157    /**
158     * Construct Deserializer using MessageContext and EnvelopeBuilder handler
159     *
160     * @param ctx is the MessageContext
161     * @param initialHandler is the EnvelopeBuilder handler
162     */

163    public DeserializationContextImpl(MessageContext ctx,
164                                      SOAPHandler initialHandler)
165    {
166       msgContext = ctx;
167
168       // If high fidelity is required, record the whole damn thing.
169
if (ctx == null || ctx.isHighFidelity())
170          recorder = new SAX2EventRecorder();
171
172       if (initialHandler instanceof EnvelopeBuilder)
173       {
174          envelope = ((EnvelopeBuilder)initialHandler).getEnvelope();
175          envelope.setRecorder(recorder);
176       }
177
178       pushElementHandler(new EnvelopeHandler(initialHandler));
179    }
180
181    /**
182     * Construct Deserializer
183     *
184     * @param is is the InputSource
185     * @param ctx is the MessageContext
186     * @param messageType is the MessageType to construct an EnvelopeBuilder
187     */

188    public DeserializationContextImpl(InputSource JavaDoc is,
189                                      MessageContext ctx,
190                                      String JavaDoc messageType)
191    {
192       msgContext = ctx;
193       EnvelopeBuilder builder = new EnvelopeBuilder(messageType, getSOAPConstants());
194       // If high fidelity is required, record the whole damn thing.
195
if (ctx == null || ctx.isHighFidelity())
196          recorder = new SAX2EventRecorder();
197
198       envelope = builder.getEnvelope();
199       envelope.setRecorder(recorder);
200
201       pushElementHandler(new EnvelopeHandler(builder));
202
203       inputSource = is;
204    }
205
206    /**
207     * returns the soap constants.
208     */

209    private SOAPConstants getSOAPConstants()
210    {
211       SOAPConstants constants = Constants.DEFAULT_SOAP_VERSION;
212       if (msgContext != null)
213          constants = msgContext.getSOAPConstants();
214       return constants;
215    }
216
217    /**
218     * Construct Deserializer
219     *
220     * @param is is the InputSource
221     * @param ctx is the MessageContext
222     * @param messageType is the MessageType to construct an EnvelopeBuilder
223     * @param env is the SOAPEnvelope to construct an EnvelopeBuilder
224     */

225    public DeserializationContextImpl(InputSource JavaDoc is,
226                                      MessageContext ctx,
227                                      String JavaDoc messageType,
228                                      SOAPEnvelopeAxisImpl env)
229    {
230       EnvelopeBuilder builder = new EnvelopeBuilder(env, messageType);
231
232       msgContext = ctx;
233
234       // If high fidelity is required, record the whole damn thing.
235
if (ctx == null || ctx.isHighFidelity())
236          recorder = new SAX2EventRecorder();
237
238       envelope = builder.getEnvelope();
239       envelope.setRecorder(recorder);
240
241       pushElementHandler(new EnvelopeHandler(builder));
242
243       inputSource = is;
244    }
245
246    /**
247     * Create a parser and parse the inputSource
248     */

249    public void parse() throws SAXException JavaDoc
250    {
251       if (inputSource != null)
252       {
253          SAXParser JavaDoc parser = XMLUtils.getSAXParser();
254          try
255          {
256             parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);
257             parser.parse(inputSource, this);
258
259             try
260             {
261                // cleanup - so that the parser can be reused.
262
parser.setProperty("http://xml.org/sax/properties/lexical-handler", nullLexicalHandler);
263             }
264             catch (SAXException JavaDoc se)
265             {
266                // Ignore.
267
}
268          }
269          catch (IOException JavaDoc e)
270          {
271             throw new SAXException JavaDoc(e);
272          }
273          inputSource = null;
274       }
275    }
276
277    /**
278     * Get current MessageElement
279     */

280    public SOAPElementAxisImpl getCurElement()
281    {
282       return curElement;
283    }
284
285    /**
286     * Set current MessageElement
287     */

288    public void setCurElement(SOAPElementAxisImpl el)
289    {
290       curElement = el;
291       if (curElement != null && curElement.getRecorder() != recorder)
292       {
293          recorder = curElement.getRecorder();
294       }
295    }
296
297
298    /**
299     * Get MessageContext
300     */

301    public MessageContext getMessageContext()
302    {
303       return msgContext;
304    }
305
306    /**
307     * Get Envelope
308     */

309    public SOAPEnvelopeAxisImpl getEnvelope()
310    {
311       return envelope;
312    }
313
314    /**
315     * Get Event Recorder
316     */

317    public SAX2EventRecorder getRecorder()
318    {
319       return recorder;
320    }
321
322    /**
323     * Set Event Recorder
324     */

325    public void setRecorder(SAX2EventRecorder recorder)
326    {
327       this.recorder = recorder;
328    }
329
330    /**
331     * Get the Namespace Mappings. Returns null if none are present.
332     */

333    public ArrayList JavaDoc getCurrentNSMappings()
334    {
335       return namespaces.cloneFrame();
336    }
337
338    /**
339     * Get the Namespace for a particular prefix
340     */

341    public String JavaDoc getNamespaceURI(String JavaDoc prefix)
342    {
343       String JavaDoc result = namespaces.getNamespaceURI(prefix);
344       if (result != null)
345          return result;
346
347       if (curElement != null)
348          return curElement.getNamespaceURI(prefix);
349
350       return null;
351    }
352
353    /**
354     * Construct a QName from a string of the form <prefix>:<localName>
355     *
356     * @param qNameStr is the prefixed name from the xml text
357     * @return QName
358     */

359    public QName JavaDoc getQNameFromString(String JavaDoc qNameStr)
360    {
361       if (qNameStr == null)
362          return null;
363
364       // OK, this is a QName, so look up the prefix in our current mappings.
365
int i = qNameStr.indexOf(':');
366       String JavaDoc nsURI;
367       if (i == -1)
368       {
369          nsURI = getNamespaceURI("");
370       }
371       else
372       {
373          nsURI = getNamespaceURI(qNameStr.substring(0, i));
374       }
375
376       return new QName JavaDoc(nsURI, qNameStr.substring(i + 1));
377    }
378
379    /**
380     * Create a QName for the type of the element defined by localName and
381     * namespace from the XSI type.
382     *
383     * @param namespace of the element
384     * @param localName is the local name of the element
385     * @param attrs are the attributes on the element
386     */

387    public QName JavaDoc getTypeFromXSITypeAttr(String JavaDoc namespace, String JavaDoc localName,
388                                        Attributes attrs)
389    {
390       // Check for type
391
String JavaDoc type = Constants.getValue(attrs, Constants.URIS_SCHEMA_XSI,
392               "type");
393       if (type != null)
394       {
395          // Return the type attribute value converted to a QName
396
return getQNameFromString(type);
397       }
398       return null;
399    }
400
401    /**
402     * Create a QName for the type of the element defined by localName and
403     * namespace with the specified attributes.
404     *
405     * @param namespace of the element
406     * @param localName is the local name of the element
407     * @param attrs are the attributes on the element
408     */

409    public QName JavaDoc getTypeFromAttributes(String JavaDoc namespace, String JavaDoc localName,
410                                       Attributes attrs)
411    {
412       QName JavaDoc typeQName = getTypeFromXSITypeAttr(namespace, localName, attrs);
413       if ((typeQName == null) && Constants.isSOAP_ENC(namespace))
414       {
415
416          // If the element is a SOAP-ENC element, the name of the element is the type.
417
// If the default type mapping accepts SOAP 1.2, then use then set
418
// the typeQName to the SOAP-ENC type.
419
// Else if the default type mapping accepts SOAP 1.1, then
420
// convert the SOAP-ENC type to the appropriate XSD Schema Type.
421
if (namespace.equals(Constants.URI_SOAP12_ENC))
422          {
423             typeQName = new QName JavaDoc(namespace, localName);
424          }
425          else if (localName.equals(Constants.SOAP_ARRAY.getLocalPart()))
426          {
427             typeQName = Constants.SOAP_ARRAY;
428          }
429          else if (localName.equals(Constants.SOAP_STRING.getLocalPart()))
430          {
431             typeQName = Constants.SOAP_STRING;
432          }
433          else if (localName.equals(Constants.SOAP_BOOLEAN.getLocalPart()))
434          {
435             typeQName = Constants.SOAP_BOOLEAN;
436          }
437          else if (localName.equals(Constants.SOAP_DOUBLE.getLocalPart()))
438          {
439             typeQName = Constants.SOAP_DOUBLE;
440          }
441          else if (localName.equals(Constants.SOAP_FLOAT.getLocalPart()))
442          {
443             typeQName = Constants.SOAP_FLOAT;
444          }
445          else if (localName.equals(Constants.SOAP_INT.getLocalPart()))
446          {
447             typeQName = Constants.SOAP_INT;
448          }
449          else if (localName.equals(Constants.SOAP_LONG.getLocalPart()))
450          {
451             typeQName = Constants.SOAP_LONG;
452          }
453          else if (localName.equals(Constants.SOAP_SHORT.getLocalPart()))
454          {
455             typeQName = Constants.SOAP_SHORT;
456          }
457          else if (localName.equals(Constants.SOAP_BYTE.getLocalPart()))
458          {
459             typeQName = Constants.SOAP_BYTE;
460          }
461       }
462
463       // If we still have no luck, check to see if there's an arrayType
464
// (itemType for SOAP 1.2) attribute, in which case this is almost
465
// certainly an array.
466

467       if (typeQName == null && attrs != null)
468       {
469          String JavaDoc encURI = getSOAPConstants().getEncodingURI();
470          String JavaDoc itemType = getSOAPConstants().getAttrItemType();
471          for (int i = 0; i < attrs.getLength(); i++)
472          {
473             if (encURI.equals(attrs.getURI(i)) &&
474                     itemType.equals(attrs.getLocalName(i)))
475             {
476                return new QName JavaDoc(encURI, "Array");
477             }
478          }
479       }
480
481       return typeQName;
482    }
483
484    /**
485     * Convenience method to get the Deserializer for a specific
486     * java class from its meta data.
487     *
488     * @param cls is the Class used to find the deserializer
489     * @return Deserializer
490     */

491    public Deserializer getDeserializerForClass(Class JavaDoc cls)
492    {
493 // if (cls == null) {
494
// cls = destClass;
495
// }
496
if (cls == null)
497       {
498          return null;
499       }
500       if (cls.isArray())
501       {
502          cls = cls.getComponentType();
503       }
504       if (Holder JavaDoc.class.isAssignableFrom(cls))
505       {
506          try
507          {
508             cls = cls.getField("value").getType();
509          }
510          catch (Exception JavaDoc e)
511          {
512          }
513       }
514       Deserializer dser = null;
515       try
516       {
517          Method JavaDoc method = cls.getMethod(DESERIALIZER_METHOD, DESERIALIZER_CLASSES);
518          if (method != null)
519          {
520             TypeDesc typedesc = TypeDesc.getTypeDescForClass(cls);
521             if (typedesc != null)
522             {
523                dser = (Deserializer)method.invoke(null,
524                        new Object JavaDoc[]{msgContext.getEncodingStyle(), cls, typedesc.getXmlType()});
525             }
526          }
527       }
528       catch (Exception JavaDoc e)
529       {
530          log.error(Messages.getMessage("noDeser00", cls.getName()));
531       }
532       return dser;
533    }
534
535    /**
536     * Convenenience method that returns true if the value is nil
537     * (due to the xsi:nil) attribute.
538     *
539     * @param attrs are the element attributes.
540     * @return true if xsi:nil is true
541     */

542    public boolean isNil(Attributes attrs)
543    {
544       return JavaUtils.isTrueExplicitly(Constants.getValue(attrs, Constants.QNAMES_NIL),
545               false);
546    }
547
548    /**
549     * Get a Deserializer which can turn a given xml type into a given
550     * Java type
551     */

552    public final Deserializer getDeserializer(Class JavaDoc cls, QName JavaDoc xmlType)
553    {
554       if (xmlType == null)
555          return null;
556
557       log.debug("Enter:getDeserializer: [class=" + cls + ",xmlType=" + xmlType + "]");
558
559       DeserializerFactory dserF = null;
560       Deserializer dser = null;
561       try
562       {
563          dserF = (DeserializerFactory)getTypeMapping().
564                  getDeserializer(cls, xmlType);
565       }
566       catch (JAXRPCException JavaDoc e)
567       {
568          log.error(Messages.getMessage("noFactory00", xmlType.toString()));
569       }
570       if (dserF != null)
571       {
572          try
573          {
574             dser = (Deserializer)dserF.getDeserializerAs(Constants.AXIS_SAX);
575          }
576          catch (JAXRPCException JavaDoc e)
577          {
578             log.error(Messages.getMessage("noDeser00", xmlType.toString()));
579          }
580       }
581
582       log.debug("Exit:getDeserializer: " + dser);
583       return dser;
584    }
585
586    /**
587     * Convenience method to get the Deserializer for a specific
588     * xmlType.
589     *
590     * @param xmlType is QName for a type to deserialize
591     * @return Deserializer
592     */

593    public final Deserializer getDeserializerForType(QName JavaDoc xmlType)
594    {
595       return getDeserializer(null, xmlType);
596    }
597
598    /**
599     * Get the TypeMapping for this DeserializationContext
600     */

601    public TypeMapping getTypeMapping()
602    {
603       TypeMappingRegistry tmr = msgContext.getTypeMappingRegistry();
604       return (TypeMapping)tmr.getTypeMapping(msgContext.getEncodingStyle());
605    }
606
607    /**
608     * Get the TypeMappingRegistry we're using.
609     *
610     * @return TypeMapping or null
611     */

612    public TypeMappingRegistry getTypeMappingRegistry()
613    {
614       return msgContext.getTypeMappingRegistry();
615    }
616
617    /**
618     * Get the MessageElement for the indicated id (where id is the #value of an href)
619     * If the MessageElement has not been processed, the MessageElement will
620     * be returned. If the MessageElement has been processed, the actual object
621     * value is stored with the id and this routine will return null.
622     *
623     * @param id is the value of an href attribute
624     * @return MessageElement or null
625     */

626    public SOAPElementAxisImpl getElementByID(String JavaDoc id)
627    {
628       if ((idMap != null))
629       {
630          IDResolver resolver = (IDResolver)idMap.get(id);
631          if (resolver != null)
632          {
633             Object JavaDoc ret = resolver.getReferencedObject(id);
634             if (ret instanceof SOAPElementAxisImpl)
635                return (SOAPElementAxisImpl)ret;
636          }
637       }
638
639       return null;
640    }
641
642    /**
643     * Gets the MessageElement or actual Object value associated with the href value.
644     * The return of a MessageElement indicates that the referenced element has
645     * not been processed. If it is not a MessageElement, the Object is the
646     * actual deserialized value.
647     * In addition, this method is invoked to get Object values via Attachments.
648     *
649     * @param href is the value of an href attribute (or an Attachment id)
650     * @return MessageElement other Object or null
651     */

652    public Object JavaDoc getObjectByRef(String JavaDoc href)
653    {
654       Object JavaDoc ret = null;
655       if (href != null)
656       {
657          if ((idMap != null))
658          {
659             IDResolver resolver = (IDResolver)idMap.get(href);
660             if (resolver != null)
661                ret = resolver.getReferencedObject(href);
662          }
663          if (null == ret && !href.startsWith("#"))
664          {
665             //Could this be an attachment?
666
Message msg = null;
667             if (null != (msg = msgContext.getCurrentMessage()))
668             {
669                Attachments attch = null;
670                if (null != (attch = msg.getAttachmentsImpl()))
671                {
672                   try
673                   {
674                      ret = attch.getAttachmentByReference(href);
675                   }
676                   catch (AxisFault e)
677                   {
678                      throw new RuntimeException JavaDoc(e.toString() + JavaUtils.stackToString(e));
679                   }
680                }
681             }
682          }
683       }
684
685       return ret;
686    }
687
688    /**
689     * Add the object associated with this id (where id is the value of an id= attribute,
690     * i.e. it does not start with #).
691     * This routine is called to associate the deserialized object
692     * with the id specified on the XML element.
693     *
694     * @param id (id name without the #)
695     * @param obj is the deserialized object for this id.
696     */

697    public void addObjectById(String JavaDoc id, Object JavaDoc obj)
698    {
699       // The resolver uses the href syntax as the key.
700
String JavaDoc idStr = '#' + id;
701       if ((idMap == null) || (id == null))
702          return;
703
704       IDResolver resolver = (IDResolver)idMap.get(idStr);
705       if (resolver == null)
706          return;
707
708       resolver.addReferencedObject(idStr, obj);
709       return;
710    }
711
712    /**
713     * During deserialization, an element with an HREF=#id<int>
714     * may be encountered before the element defining id=id<int> is
715     * read. In these cases, the getObjectByRef method above will
716     * return null. The deserializer is placed in a table keyed
717     * by href (a fixup table). After the element id is processed,
718     * the deserializer is informed of the value so that it can
719     * update its target(s) with the value.
720     *
721     * @param href (#id syntax)
722     * @param dser is the deserializer of the element
723     */

724    public void registerFixup(String JavaDoc href, Deserializer dser)
725    {
726       if (fixups == null)
727          fixups = new HashMap JavaDoc();
728
729       Deserializer prev = (Deserializer)fixups.put(href, dser);
730
731       // There could already be a deserializer in the fixup list
732
// for this href. If so, the easiest way to get all of the
733
// targets updated is to move the previous deserializers
734
// targets to dser.
735
if (prev != null && prev != dser)
736       {
737          dser.moveValueTargets(prev);
738          if (dser.getDefaultType() == null)
739          {
740             dser.setDefaultType(prev.getDefaultType());
741          }
742       }
743    }
744
745    /**
746     * Register the MessageElement with this id (where id is id= form without the #)
747     * This routine is called when the MessageElement with an id is read.
748     * If there is a Deserializer in our fixup list (described above),
749     * the 'fixup' deserializer is given to the MessageElement. When the
750     * MessageElement is completed, the 'fixup' deserializer is informed and
751     * it can set its targets.
752     *
753     * @param id (id name without the #)
754     * @param elem is the MessageElement
755     */

756    public void registerElementByID(String JavaDoc id, SOAPElementAxisImpl elem)
757    {
758       if (localIDs == null)
759          localIDs = new LocalIDResolver();
760
761       String JavaDoc absID = '#' + id;
762
763       localIDs.addReferencedObject(absID, elem);
764
765       registerResolverForID(absID, localIDs);
766
767       if (fixups != null)
768       {
769          Deserializer dser = (Deserializer)fixups.get(absID);
770          if (dser != null)
771          {
772             elem.setFixupDeserializer(dser);
773          }
774       }
775    }
776
777    /**
778     * Each id can have its own kind of resolver. This registers a
779     * resolver for the id.
780     */

781    public void registerResolverForID(String JavaDoc id, IDResolver resolver)
782    {
783       if ((id == null) || (resolver == null))
784       {
785          // ??? Throw nullPointerException?
786
return;
787       }
788
789       if (idMap == null)
790          idMap = new HashMap JavaDoc();
791
792       idMap.put(id, resolver);
793    }
794
795    /**
796     * Get the current position in the record.
797     */

798    public int getCurrentRecordPos()
799    {
800       if (recorder == null) return -1;
801       return recorder.getLength() - 1;
802    }
803
804    /**
805     * Get the start of the mapping position
806     */

807    public int getStartOfMappingsPos()
808    {
809       if (startOfMappingsPos == -1)
810       {
811          return getCurrentRecordPos() + 1;
812       }
813
814       return startOfMappingsPos;
815    }
816
817    /**
818     * Push the MessageElement into the recorder
819     */

820    public void pushNewElement(SOAPElementAxisImpl elem)
821    {
822       if (log.isDebugEnabled())
823       {
824          log.debug("Pushing element " + elem.getName());
825       }
826
827       if (!doneParsing && (recorder != null))
828       {
829          recorder.newElement(elem);
830       }
831
832       try
833       {
834          if (curElement != null)
835             elem.setParentElement(curElement);
836       }
837       catch (Exception JavaDoc e)
838       {
839          /*
840           * The only checked exception that may be thrown from setParent
841           * occurs if the parent already has an explicit object value,
842           * which should never occur during deserialization.
843           */

844          log.fatal(Messages.getMessage("exception00"), e);
845       }
846       curElement = elem;
847
848       if (elem.getRecorder() != recorder)
849          recorder = elem.getRecorder();
850    }
851
852    /**
853     * *************************************************************
854     * Management of sub-handlers (deserializers)
855     */

856
857    public void pushElementHandler(SOAPHandler handler)
858    {
859       if (log.isDebugEnabled())
860       {
861          log.debug(Messages.getMessage("pushHandler00", "" + handler));
862       }
863
864       if (topHandler != null) pushedDownHandlers.add(topHandler);
865       topHandler = handler;
866    }
867
868    /**
869     * Replace the handler at the top of the stack.
870     * <p/>
871     * This is only used when we have a placeholder Deserializer
872     * for a referenced object which doesn't know its type until we
873     * hit the referent.
874     */

875    public void replaceElementHandler(SOAPHandler handler)
876    {
877       topHandler = handler;
878    }
879
880    public SOAPHandler popElementHandler()
881    {
882       SOAPHandler result = topHandler;
883
884       int size = pushedDownHandlers.size();
885       if (size > 0)
886       {
887          topHandler = (SOAPHandler)pushedDownHandlers.remove(size - 1);
888       }
889       else
890       {
891          topHandler = null;
892       }
893
894       if (log.isDebugEnabled())
895       {
896          if (result == null)
897          {
898             log.debug(Messages.getMessage("popHandler00", "(null)"));
899          }
900          else
901          {
902             log.debug(Messages.getMessage("popHandler00", "" + result));
903          }
904       }
905
906       return result;
907    }
908
909    boolean processingRef = false;
910
911    public void setProcessingRef(boolean ref)
912    {
913       processingRef = ref;
914    }
915
916    public boolean isProcessingRef()
917    {
918       return processingRef;
919    }
920
921    /**
922     * *************************************************************
923     * SAX event handlers
924     */

925    public void startDocument() throws SAXException JavaDoc
926    {
927       // Should never receive this in the midst of a parse.
928
if (!doneParsing && (recorder != null))
929          recorder.startDocument();
930    }
931
932    /**
933     * endDocument is invoked at the end of the document.
934     */

935    public void endDocument() throws SAXException JavaDoc
936    {
937       if (log.isDebugEnabled())
938       {
939          log.debug("Enter: DeserializationContextImpl::endDocument()");
940       }
941       if (!doneParsing && (recorder != null))
942          recorder.endDocument();
943
944       doneParsing = true;
945
946       if (log.isDebugEnabled())
947       {
948          log.debug("Exit: DeserializationContextImpl::endDocument()");
949       }
950    }
951
952    /**
953     * Return if done parsing document.
954     */

955    public boolean isDoneParsing()
956    {
957       return doneParsing;
958    }
959
960    /**
961     * Record the current set of prefix mappings in the nsMappings table.
962     * <p/>
963     * !!! We probably want to have this mapping be associated with the
964     * MessageElements, since they may potentially need access to them
965     * long after the end of the prefix mapping here. (example:
966     * when we need to record a long string of events scanning forward
967     * in the document to find an element with a particular ID.)
968     */

969    public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
970            throws SAXException JavaDoc
971    {
972       if (log.isDebugEnabled())
973          log.debug("Enter: DeserializationContextImpl::startPrefixMapping(" + prefix + ", " + uri + ")");
974
975       // This is a workaround for http://jira.jboss.com/jira/browse/JBWS-64
976
if ("".equals(uri))
977       {
978          log.warn("Ignoring invalid namespace mapping: [prefix=" + prefix + ",uri=" + uri + "]");
979          return;
980       }
981
982       if (!doneParsing && (recorder != null))
983       {
984          recorder.startPrefixMapping(prefix, uri);
985       }
986
987       if (startOfMappingsPos == -1)
988       {
989          namespaces.push();
990          startOfMappingsPos = getCurrentRecordPos();
991       }
992
993       if (prefix != null)
994       {
995          namespaces.add(uri, prefix);
996       }
997       else
998       {
999          namespaces.add(uri, "");
1000      }
1001
1002      if (!haveSeenSchemaNS && msgContext != null)
1003      {
1004         // If we haven't yet seen a schema namespace, check if this
1005
// is one. If so, set the SchemaVersion appropriately.
1006
// Hopefully the schema def is on the outermost element so we
1007
// get this over with quickly.
1008
for (int i = 0; !haveSeenSchemaNS && i < schemaVersions.length;
1009              i++)
1010         {
1011            SchemaVersion schemaVersion = schemaVersions[i];
1012            if (uri.equals(schemaVersion.getXsdURI()) ||
1013                    uri.equals(schemaVersion.getXsiURI()))
1014            {
1015               msgContext.setSchemaVersion(schemaVersion);
1016               haveSeenSchemaNS = true;
1017            }
1018         }
1019      }
1020
1021      if (topHandler != null)
1022      {
1023         topHandler.startPrefixMapping(prefix, uri);
1024      }
1025
1026      if (log.isDebugEnabled())
1027         log.debug("Exit: DeserializationContextImpl::startPrefixMapping()");
1028   }
1029
1030   public void endPrefixMapping(String JavaDoc prefix)
1031           throws SAXException JavaDoc
1032   {
1033      if (log.isDebugEnabled())
1034      {
1035         log.debug("Enter: DeserializationContextImpl::endPrefixMapping(" + prefix + ")");
1036      }
1037
1038      if (!doneParsing && (recorder != null))
1039      {
1040         recorder.endPrefixMapping(prefix);
1041      }
1042
1043      if (topHandler != null)
1044      {
1045         topHandler.endPrefixMapping(prefix);
1046      }
1047
1048      if (log.isDebugEnabled())
1049      {
1050         log.debug("Exit: DeserializationContextImpl::endPrefixMapping()");
1051      }
1052   }
1053
1054   public void setDocumentLocator(Locator JavaDoc locator)
1055   {
1056      if (!doneParsing && (recorder != null))
1057      {
1058         recorder.setDocumentLocator(locator);
1059      }
1060      this.locator = locator;
1061   }
1062
1063   public Locator JavaDoc getDocumentLocator()
1064   {
1065      return locator;
1066   }
1067
1068   public void characters(char[] p1, int p2, int p3) throws SAXException JavaDoc
1069   {
1070      if (!doneParsing && (recorder != null))
1071      {
1072         recorder.characters(p1, p2, p3);
1073
1074         if (curElement != null)
1075         {
1076            if (curElementContent == null)
1077               curElementContent = new StringBuffer JavaDoc();
1078
1079            String JavaDoc text = new String JavaDoc(p1, p2, p3);
1080            curElementContent.append(text);
1081         }
1082      }
1083      if (topHandler != null)
1084      {
1085         topHandler.characters(p1, p2, p3);
1086      }
1087   }
1088
1089   public void ignorableWhitespace(char[] p1, int p2, int p3) throws SAXException JavaDoc
1090   {
1091      if (!doneParsing && (recorder != null))
1092      {
1093         recorder.ignorableWhitespace(p1, p2, p3);
1094      }
1095      if (topHandler != null)
1096      {
1097         topHandler.ignorableWhitespace(p1, p2, p3);
1098      }
1099   }
1100
1101   public void processingInstruction(String JavaDoc p1, String JavaDoc p2) throws SAXException JavaDoc
1102   {
1103      // must throw an error since SOAP 1.1 doesn't allow
1104
// processing instructions anywhere in the message
1105
throw new SAXException JavaDoc(Messages.getMessage("noInstructions00"));
1106   }
1107
1108   public void skippedEntity(String JavaDoc p1) throws SAXException JavaDoc
1109   {
1110      if (!doneParsing && (recorder != null))
1111      {
1112         recorder.skippedEntity(p1);
1113      }
1114      topHandler.skippedEntity(p1);
1115   }
1116
1117   /**
1118    * startElement is called when an element is read. This is the big work-horse.
1119    * <p/>
1120    * This guy also handles monitoring the recording depth if we're recording
1121    * (so we know when to stop).
1122    */

1123   public void startElement(String JavaDoc namespace, String JavaDoc localName,
1124                            String JavaDoc qName, Attributes attributes)
1125           throws SAXException JavaDoc
1126   {
1127      if (log.isDebugEnabled())
1128      {
1129         log.debug("Enter: DeserializationContextImpl::startElement(" + namespace + ", " + localName + ")");
1130      }
1131
1132      if (attributes == null || attributes.getLength() == 0)
1133      {
1134         attributes = NullAttributes.singleton;
1135      }
1136      else
1137      {
1138         attributes = new AttributesImpl JavaDoc(attributes);
1139
1140         SOAPConstants soapConstants = getSOAPConstants();
1141         if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
1142         {
1143            if (attributes.getValue(soapConstants.getAttrHref()) != null &&
1144                    attributes.getValue(Constants.ATTR_ID) != null)
1145            {
1146
1147               AxisFault fault = new AxisFault(Constants.FAULT_SOAP12_SENDER,
1148                       null, Messages.getMessage("noIDandHREFonSameElement"), null, null, null);
1149
1150               throw new SAXException JavaDoc(fault);
1151
1152            }
1153         }
1154
1155      }
1156
1157      SOAPHandler nextHandler = null;
1158
1159      String JavaDoc prefix = "";
1160      int idx = qName.indexOf(':');
1161      if (idx > 0)
1162      {
1163         prefix = qName.substring(0, idx);
1164      }
1165
1166      if (topHandler != null)
1167      {
1168         nextHandler = topHandler.onStartChild(namespace,
1169                 localName,
1170                 prefix,
1171                 attributes,
1172                 this);
1173      }
1174
1175      if (nextHandler == null)
1176      {
1177         nextHandler = new SOAPHandler();
1178      }
1179
1180      pushElementHandler(nextHandler);
1181
1182      nextHandler.startElement(namespace, localName, prefix,
1183              attributes, this);
1184
1185      if (!doneParsing && (recorder != null))
1186      {
1187         recorder.startElement(namespace, localName, qName,
1188                 attributes);
1189         if (!doneParsing)
1190         {
1191            curElement.setContentsIndex(recorder.getLength());
1192         }
1193      }
1194
1195      if (startOfMappingsPos != -1)
1196      {
1197         startOfMappingsPos = -1;
1198      }
1199      else
1200      {
1201         // Push an empty frame if there are no mappings
1202
namespaces.push();
1203      }
1204
1205      if (log.isDebugEnabled())
1206      {
1207         log.debug("Exit: DeserializationContextImpl::startElement()");
1208      }
1209   }
1210
1211   /**
1212    * endElement is called at the end tag of an element
1213    */

1214   public void endElement(String JavaDoc namespace, String JavaDoc localName, String JavaDoc qName)
1215           throws SAXException JavaDoc
1216   {
1217      if (log.isDebugEnabled())
1218      {
1219         log.debug("Enter: DeserializationContextImpl::endElement(" + namespace + ", " + localName + ")");
1220      }
1221
1222      if (!doneParsing && (recorder != null))
1223      {
1224         String JavaDoc text = null;
1225         try
1226         {
1227            if (curElementContent != null)
1228            {
1229               text = curElementContent.toString().trim();
1230               if (text.length() > 0)
1231               {
1232                  log.debug("addTextNode: '" + text + "'");
1233                  curElement.addTextNode(text);
1234               }
1235               curElementContent = null;
1236            }
1237         }
1238         catch (SOAPException JavaDoc e)
1239         {
1240            throw new SAXException JavaDoc("Cannot add Text child: " + text);
1241         }
1242
1243         recorder.endElement(namespace, localName, qName);
1244      }
1245
1246      try
1247      {
1248         SOAPHandler handler = popElementHandler();
1249         handler.endElement(namespace, localName, this);
1250
1251         if (topHandler != null)
1252         {
1253            topHandler.onEndChild(namespace, localName, this);
1254         }
1255         else
1256         {
1257            // We should be done!
1258
}
1259
1260      }
1261      finally
1262      {
1263         if (curElement != null)
1264         {
1265            curElement = (SOAPElementAxisImpl)curElement.getParentElement();
1266         }
1267
1268         namespaces.pop();
1269
1270         if (log.isDebugEnabled())
1271         {
1272            String JavaDoc name = curElement != null ?
1273                    curElement.getClass().getName() + ":" +
1274                    curElement.getName() : null;
1275            log.debug("Popped element stack to " + name);
1276            log.debug("Exit: DeserializationContextImpl::endElement()");
1277         }
1278      }
1279   }
1280
1281   /**
1282    * This class is used to map ID's to an actual value Object or Message
1283    */

1284   private static class LocalIDResolver implements IDResolver
1285   {
1286      HashMap JavaDoc idMap = null;
1287
1288      /**
1289       * Add object associated with id
1290       */

1291      public void addReferencedObject(String JavaDoc id, Object JavaDoc referent)
1292      {
1293         if (idMap == null)
1294         {
1295            idMap = new HashMap JavaDoc();
1296         }
1297
1298         idMap.put(id, referent);
1299      }
1300
1301      /**
1302       * Get object referenced by href
1303       */

1304      public Object JavaDoc getReferencedObject(String JavaDoc href)
1305      {
1306         if ((idMap == null) || (href == null))
1307         {
1308            return null;
1309         }
1310         return idMap.get(href);
1311      }
1312   }
1313
1314   public void startDTD(java.lang.String JavaDoc name,
1315                        java.lang.String JavaDoc publicId,
1316                        java.lang.String JavaDoc systemId)
1317           throws SAXException JavaDoc
1318   {
1319      /* It is possible for a malicious user to send us bad stuff in
1320         the <!DOCTYPE ../> tag that will cause a denial of service
1321         Example:
1322         <?xml version="1.0" ?>
1323          <!DOCTYPE foobar [
1324              <!ENTITY x0 "hello">
1325              <!ENTITY x1 "&x0;&x0;">
1326              <!ENTITY x2 "&x1;&x1;">
1327                ...
1328              <!ENTITY x99 "&x98;&x98;">
1329              <!ENTITY x100 "&x99;&x99;">
1330          ]>
1331      */

1332      throw new SAXException JavaDoc(Messages.getMessage("noInstructions00"));
1333      /* if (recorder != null)
1334          recorder.startDTD(name, publicId, systemId);
1335      */

1336   }
1337
1338   public void endDTD()
1339           throws SAXException JavaDoc
1340   {
1341      if (recorder != null)
1342         recorder.endDTD();
1343   }
1344
1345   public void startEntity(java.lang.String JavaDoc name)
1346           throws SAXException JavaDoc
1347   {
1348      if (recorder != null)
1349         recorder.startEntity(name);
1350   }
1351
1352   public void endEntity(java.lang.String JavaDoc name)
1353           throws SAXException JavaDoc
1354   {
1355      if (recorder != null)
1356         recorder.endEntity(name);
1357   }
1358
1359   public void startCDATA()
1360           throws SAXException JavaDoc
1361   {
1362      if (recorder != null)
1363         recorder.startCDATA();
1364   }
1365
1366   public void endCDATA()
1367           throws SAXException JavaDoc
1368   {
1369      if (recorder != null)
1370         recorder.endCDATA();
1371   }
1372
1373   public void comment(char[] ch,
1374                       int start,
1375                       int length)
1376           throws SAXException JavaDoc
1377   {
1378      if (recorder != null)
1379         recorder.comment(ch, start, length);
1380   }
1381
1382   public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
1383   {
1384      return XMLUtils.getEmptyInputSource();
1385   }
1386   
1387   /** We only need one instance of this dummy handler to set into the parsers. */
1388   private static final NullLexicalHandler nullLexicalHandler = new NullLexicalHandler();
1389
1390   /**
1391    * It is illegal to set the lexical-handler property to null. To facilitate
1392    * discarding the heavily loaded instance of DeserializationContextImpl from
1393    * the SAXParser instance that is kept in the Stack maintained by XMLUtils
1394    * we use this class.
1395    */

1396   private static class NullLexicalHandler implements LexicalHandler JavaDoc
1397   {
1398      public void startDTD(String JavaDoc arg0, String JavaDoc arg1, String JavaDoc arg2) throws SAXException JavaDoc {}
1399      public void endDTD() throws SAXException JavaDoc {}
1400      public void startEntity(String JavaDoc arg0) throws SAXException JavaDoc {}
1401      public void endEntity(String JavaDoc arg0) throws SAXException JavaDoc {}
1402      public void startCDATA() throws SAXException JavaDoc {}
1403      public void endCDATA() throws SAXException JavaDoc {}
1404      public void comment(char[] arg0, int arg1, int arg2) throws SAXException JavaDoc {}
1405   }
1406}
1407
1408
Popular Tags