KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > encoding > DeserializationContext


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 package org.apache.axis.encoding;
19
20 import org.apache.axis.MessageContext;
21 import org.apache.axis.Constants;
22 import org.apache.axis.Message;
23 import org.apache.axis.AxisFault;
24 import org.apache.axis.constants.Use;
25 import org.apache.axis.attachments.Attachments;
26 import org.apache.axis.description.TypeDesc;
27 import org.apache.axis.soap.SOAPConstants;
28 import org.apache.axis.utils.NSStack;
29 import org.apache.axis.utils.XMLUtils;
30 import org.apache.axis.utils.JavaUtils;
31 import org.apache.axis.utils.Messages;
32 import org.apache.axis.utils.cache.MethodCache;
33 import org.apache.axis.schema.SchemaVersion;
34 import org.apache.axis.components.logger.LogFactory;
35 import org.apache.axis.message.IDResolver;
36 import org.apache.axis.message.MessageElement;
37 import org.apache.axis.message.SAX2EventRecorder;
38 import org.apache.axis.message.SOAPEnvelope;
39 import org.apache.axis.message.SOAPHandler;
40 import org.apache.axis.message.EnvelopeBuilder;
41 import org.apache.axis.message.EnvelopeHandler;
42 import org.apache.axis.message.NullAttributes;
43 import org.apache.commons.logging.Log;
44 import org.xml.sax.Attributes JavaDoc;
45 import org.xml.sax.SAXException JavaDoc;
46 import org.xml.sax.Locator JavaDoc;
47 import org.xml.sax.InputSource JavaDoc;
48 import org.xml.sax.ext.LexicalHandler JavaDoc;
49 import org.xml.sax.helpers.AttributesImpl JavaDoc;
50 import org.xml.sax.helpers.DefaultHandler JavaDoc;
51
52 import javax.xml.namespace.QName JavaDoc;
53 import javax.xml.parsers.SAXParser JavaDoc;
54 import javax.xml.rpc.JAXRPCException JavaDoc;
55 import java.util.ArrayList JavaDoc;
56 import java.util.HashMap JavaDoc;
57 import java.io.IOException JavaDoc;
58 import java.lang.reflect.Method JavaDoc;
59
60 /**
61  * This interface describes the AXIS DeserializationContext, note that
62  * an AXIS compliant DeserializationContext must extend the org.xml.sax.helpers.DefaultHandler.
63  */

64
65 public class DeserializationContext extends DefaultHandler JavaDoc
66         implements javax.xml.rpc.encoding.DeserializationContext JavaDoc, LexicalHandler JavaDoc {
67     protected static Log log =
68             LogFactory.getLog(DeserializationContext.class.getName());
69
70     // invariant member variable to track low-level logging requirements
71
// we cache this once per instance lifecycle to avoid repeated lookups
72
// in heavily used code.
73
private final boolean debugEnabled = log.isDebugEnabled();
74
75     static final SchemaVersion schemaVersions[] = new SchemaVersion [] {
76         SchemaVersion.SCHEMA_1999,
77         SchemaVersion.SCHEMA_2000,
78         SchemaVersion.SCHEMA_2001,
79     };
80
81     private NSStack namespaces = new NSStack();
82
83     private Locator JavaDoc locator;
84
85     // Class used for deserialization using class metadata from
86
// downstream deserializers
87
private Class JavaDoc destClass;
88
89     // for performance reasons, keep the top of the stack separate from
90
// the remainder of the handlers, and therefore readily available.
91
private SOAPHandler topHandler = null;
92     private ArrayList JavaDoc pushedDownHandlers = new ArrayList JavaDoc();
93
94     //private SAX2EventRecorder recorder = new SAX2EventRecorder();
95
private SAX2EventRecorder recorder = null;
96     private SOAPEnvelope envelope;
97
98     /* A map of IDs -> IDResolvers */
99     private HashMap JavaDoc idMap;
100     private LocalIDResolver localIDs;
101
102     private HashMap JavaDoc fixups;
103
104     static final SOAPHandler nullHandler = new SOAPHandler();
105
106     protected MessageContext msgContext;
107
108     private boolean doneParsing = false;
109     protected InputSource JavaDoc inputSource = null;
110
111     private MessageElement curElement;
112
113     protected int startOfMappingsPos = -1;
114
115     private static final Class JavaDoc[] DESERIALIZER_CLASSES =
116             new Class JavaDoc[] {String JavaDoc.class, Class JavaDoc.class, QName JavaDoc.class};
117     private static final String JavaDoc DESERIALIZER_METHOD = "getDeserializer";
118
119     // This is a hack to associate the first schema namespace we see with
120
// the correct SchemaVersion. It assumes people won't often be mixing
121
// schema versions in a given document, which I think is OK. --Glen
122
protected boolean haveSeenSchemaNS = false;
123
124     public void deserializing(boolean isDeserializing) {
125         doneParsing = isDeserializing;
126     }
127
128     /**
129      * Construct Deserializer using MessageContext and EnvelopeBuilder handler
130      * @param ctx is the MessageContext
131      * @param initialHandler is the EnvelopeBuilder handler
132      */

133     public DeserializationContext(MessageContext ctx,
134                                   SOAPHandler initialHandler)
135     {
136         msgContext = ctx;
137
138         // If high fidelity is required, record the whole damn thing.
139
if (ctx == null || ctx.isHighFidelity())
140             recorder = new SAX2EventRecorder();
141
142         if (initialHandler instanceof EnvelopeBuilder) {
143             envelope = ((EnvelopeBuilder)initialHandler).getEnvelope();
144             envelope.setRecorder(recorder);
145         }
146
147         pushElementHandler(new EnvelopeHandler(initialHandler));
148     }
149
150     /**
151      * Construct Deserializer
152      * @param is is the InputSource
153      * @param ctx is the MessageContext
154      * @param messageType is the MessageType to construct an EnvelopeBuilder
155      */

156     public DeserializationContext(InputSource JavaDoc is,
157                                   MessageContext ctx,
158                                   String JavaDoc messageType)
159     {
160         msgContext = ctx;
161         EnvelopeBuilder builder = new EnvelopeBuilder(messageType, null);
162         // If high fidelity is required, record the whole damn thing.
163
if (ctx == null || ctx.isHighFidelity())
164             recorder = new SAX2EventRecorder();
165
166         envelope = builder.getEnvelope();
167         envelope.setRecorder(recorder);
168
169         pushElementHandler(new EnvelopeHandler(builder));
170
171         inputSource = is;
172     }
173
174     private SOAPConstants soapConstants = null;
175
176     /**
177      * returns the soap constants.
178      */

179     public SOAPConstants getSOAPConstants(){
180         if (soapConstants != null)
181             return soapConstants;
182         if (msgContext != null) {
183             soapConstants = msgContext.getSOAPConstants();
184             return soapConstants;
185         } else {
186             return Constants.DEFAULT_SOAP_VERSION;
187         }
188     }
189
190     /**
191      * Construct Deserializer
192      * @param is is the InputSource
193      * @param ctx is the MessageContext
194      * @param messageType is the MessageType to construct an EnvelopeBuilder
195      * @param env is the SOAPEnvelope to construct an EnvelopeBuilder
196      */

197     public DeserializationContext(InputSource JavaDoc is,
198                                   MessageContext ctx,
199                                   String JavaDoc messageType,
200                                   SOAPEnvelope env)
201     {
202         EnvelopeBuilder builder = new EnvelopeBuilder(env, messageType);
203
204         msgContext = ctx;
205
206         // If high fidelity is required, record the whole damn thing.
207
if (ctx == null || ctx.isHighFidelity())
208             recorder = new SAX2EventRecorder();
209
210         envelope = builder.getEnvelope();
211         envelope.setRecorder(recorder);
212
213         pushElementHandler(new EnvelopeHandler(builder));
214
215         inputSource = is;
216     }
217
218     /**
219      * Create a parser and parse the inputSource
220      */

221     public void parse() throws SAXException JavaDoc
222     {
223         if (inputSource != null) {
224             SAXParser JavaDoc parser = XMLUtils.getSAXParser();
225             try {
226                 parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);
227                 parser.parse(inputSource, this);
228
229                 try {
230                     // cleanup - so that the parser can be reused.
231
parser.setProperty("http://xml.org/sax/properties/lexical-handler", nullLexicalHandler);
232                 } catch (Exception JavaDoc e){
233                     // Ignore.
234
}
235
236                 // only release the parser for reuse if there wasn't an
237
// error. While parsers should be reusable, don't trust
238
// parsers that died to clean up appropriately.
239
XMLUtils.releaseSAXParser(parser);
240             } catch (IOException JavaDoc e) {
241                 throw new SAXException JavaDoc(e);
242             }
243             inputSource = null;
244         }
245     }
246
247     /**
248      * Get current MessageElement
249      **/

250     public MessageElement getCurElement() {
251         return curElement;
252     }
253
254     /**
255      * Set current MessageElement
256      **/

257     public void setCurElement(MessageElement el)
258     {
259         curElement = el;
260         if (curElement != null && curElement.getRecorder() != recorder) {
261             recorder = curElement.getRecorder();
262         }
263     }
264
265
266     /**
267      * Get MessageContext
268      */

269     public MessageContext getMessageContext()
270     {
271         return msgContext;
272     }
273
274     /**
275      * Returns this context's encoding style. If we've got a message
276      * context then we'll get the style from that; otherwise we'll
277      * return a default.
278      *
279      * @return a <code>String</code> value
280      */

281     public String JavaDoc getEncodingStyle()
282     {
283         return msgContext == null ?
284                 Use.ENCODED.getEncoding() : msgContext.getEncodingStyle();
285     }
286
287     /**
288      * Get Envelope
289      */

290     public SOAPEnvelope getEnvelope()
291     {
292         return envelope;
293     }
294
295     /**
296      * Get Event Recorder
297      */

298     public SAX2EventRecorder getRecorder()
299     {
300         return recorder;
301     }
302
303     /**
304      * Set Event Recorder
305      */

306     public void setRecorder(SAX2EventRecorder recorder)
307     {
308         this.recorder = recorder;
309     }
310
311     /**
312      * Get the Namespace Mappings. Returns null if none are present.
313      **/

314     public ArrayList JavaDoc getCurrentNSMappings()
315     {
316         return namespaces.cloneFrame();
317     }
318
319     /**
320      * Get the Namespace for a particular prefix
321      */

322     public String JavaDoc getNamespaceURI(String JavaDoc prefix)
323     {
324         String JavaDoc result = namespaces.getNamespaceURI(prefix);
325         if (result != null)
326             return result;
327
328         if (curElement != null)
329             return curElement.getNamespaceURI(prefix);
330
331         return null;
332     }
333
334     /**
335      * Construct a QName from a string of the form <prefix>:<localName>
336      * @param qNameStr is the prefixed name from the xml text
337      * @return QName
338      */

339     public QName JavaDoc getQNameFromString(String JavaDoc qNameStr)
340     {
341         if (qNameStr == null)
342             return null;
343
344         // OK, this is a QName, so look up the prefix in our current mappings.
345
int i = qNameStr.indexOf(':');
346         String JavaDoc nsURI;
347         if (i == -1) {
348             nsURI = getNamespaceURI("");
349         } else {
350             nsURI = getNamespaceURI(qNameStr.substring(0, i));
351         }
352
353         return new QName JavaDoc(nsURI, qNameStr.substring(i + 1));
354     }
355
356     /**
357      * Create a QName for the type of the element defined by localName and
358      * namespace from the XSI type.
359      * @param namespace of the element
360      * @param localName is the local name of the element
361      * @param attrs are the attributes on the element
362      */

363     public QName JavaDoc getTypeFromXSITypeAttr(String JavaDoc namespace, String JavaDoc localName,
364                                           Attributes attrs) {
365         // Check for type
366
String JavaDoc type = Constants.getValue(attrs, Constants.URIS_SCHEMA_XSI,
367                                          "type");
368         if (type != null) {
369             // Return the type attribute value converted to a QName
370
return getQNameFromString(type);
371         }
372         return null;
373     }
374
375     /**
376      * Create a QName for the type of the element defined by localName and
377      * namespace with the specified attributes.
378      * @param namespace of the element
379      * @param localName is the local name of the element
380      * @param attrs are the attributes on the element
381      */

382     public QName JavaDoc getTypeFromAttributes(String JavaDoc namespace, String JavaDoc localName,
383                                        Attributes attrs)
384     {
385         QName JavaDoc typeQName = getTypeFromXSITypeAttr(namespace, localName, attrs);
386         if ( (typeQName == null) && Constants.isSOAP_ENC(namespace) ) {
387
388             // If the element is a SOAP-ENC element, the name of the element is the type.
389
// If the default type mapping accepts SOAP 1.2, then use then set
390
// the typeQName to the SOAP-ENC type.
391
// Else if the default type mapping accepts SOAP 1.1, then
392
// convert the SOAP-ENC type to the appropriate XSD Schema Type.
393
if (namespace.equals(Constants.URI_SOAP12_ENC)) {
394                 typeQName = new QName JavaDoc(namespace, localName);
395             } else if (localName.equals(Constants.SOAP_ARRAY.getLocalPart())) {
396                 typeQName = Constants.SOAP_ARRAY;
397             } else if (localName.equals(Constants.SOAP_STRING.getLocalPart())) {
398                 typeQName = Constants.SOAP_STRING;
399             } else if (localName.equals(Constants.SOAP_BOOLEAN.getLocalPart())) {
400                 typeQName = Constants.SOAP_BOOLEAN;
401             } else if (localName.equals(Constants.SOAP_DOUBLE.getLocalPart())) {
402                 typeQName = Constants.SOAP_DOUBLE;
403             } else if (localName.equals(Constants.SOAP_FLOAT.getLocalPart())) {
404                 typeQName = Constants.SOAP_FLOAT;
405             } else if (localName.equals(Constants.SOAP_INT.getLocalPart())) {
406                 typeQName = Constants.SOAP_INT;
407             } else if (localName.equals(Constants.SOAP_LONG.getLocalPart())) {
408                 typeQName = Constants.SOAP_LONG;
409             } else if (localName.equals(Constants.SOAP_SHORT.getLocalPart())) {
410                 typeQName = Constants.SOAP_SHORT;
411             } else if (localName.equals(Constants.SOAP_BYTE.getLocalPart())) {
412                 typeQName = Constants.SOAP_BYTE;
413             }
414         }
415
416         // If we still have no luck, check to see if there's an arrayType
417
// (itemType for SOAP 1.2) attribute, in which case this is almost
418
// certainly an array.
419

420         if (typeQName == null && attrs != null) {
421             String JavaDoc encURI = getSOAPConstants().getEncodingURI();
422             String JavaDoc itemType = getSOAPConstants().getAttrItemType();
423             for (int i = 0; i < attrs.getLength(); i++) {
424                 if (encURI.equals(attrs.getURI(i)) &&
425                         itemType.equals(attrs.getLocalName(i))) {
426                     return new QName JavaDoc(encURI, "Array");
427                 }
428             }
429         }
430
431         return typeQName;
432     }
433
434     /**
435      * Convenenience method that returns true if the value is nil
436      * (due to the xsi:nil) attribute.
437      * @param attrs are the element attributes.
438      * @return true if xsi:nil is true
439      */

440     public boolean isNil(Attributes attrs) {
441         return JavaUtils.isTrueExplicitly(
442                     Constants.getValue(attrs, Constants.QNAMES_NIL),
443                     false);
444     }
445
446     /**
447      * Get a Deserializer which can turn a given xml type into a given
448      * Java type
449      */

450     public final Deserializer getDeserializer(Class JavaDoc cls, QName JavaDoc xmlType) {
451         if (xmlType == null)
452             return null;
453
454         DeserializerFactory dserF = null;
455         Deserializer dser = null;
456         try {
457             dserF = (DeserializerFactory) getTypeMapping().
458                     getDeserializer(cls, xmlType);
459         } catch (JAXRPCException JavaDoc e) {
460             log.error(Messages.getMessage("noFactory00", xmlType.toString()));
461         }
462         if (dserF != null) {
463             try {
464                 dser = (Deserializer) dserF.getDeserializerAs(Constants.AXIS_SAX);
465             } catch (JAXRPCException JavaDoc e) {
466                 log.error(Messages.getMessage("noDeser00", xmlType.toString()));
467             }
468         }
469         return dser;
470     }
471
472     /**
473      * Convenience method to get the Deserializer for a specific
474      * java class from its meta data.
475      * @param cls is the Class used to find the deserializer
476      * @return Deserializer
477      */

478     public Deserializer getDeserializerForClass(Class JavaDoc cls) {
479         if (cls == null) {
480            cls = destClass;
481         }
482         if (cls == null) {
483             return null;
484         }
485 // if (cls.isArray()) {
486
// cls = cls.getComponentType();
487
// }
488
if (javax.xml.rpc.holders.Holder JavaDoc.class.isAssignableFrom(cls)) {
489             try {
490                 cls = cls.getField("value").getType();
491             } catch (Exception JavaDoc e) {
492             }
493         }
494
495         Deserializer dser = null;
496
497         QName JavaDoc type = getTypeMapping().getTypeQName(cls);
498         dser = getDeserializer(cls, type);
499         if (dser != null)
500             return dser;
501
502         try {
503             Method JavaDoc method =
504                 MethodCache.getInstance().getMethod(cls,
505                                                     DESERIALIZER_METHOD,
506                                                     DESERIALIZER_CLASSES);
507             if (method != null) {
508                 TypeDesc typedesc = TypeDesc.getTypeDescForClass(cls);
509                 if (typedesc != null) {
510                     dser = (Deserializer) method.invoke(null,
511                         new Object JavaDoc[] {getEncodingStyle(), cls, typedesc.getXmlType()});
512                 }
513             }
514         } catch (Exception JavaDoc e) {
515             log.error(Messages.getMessage("noDeser00", cls.getName()));
516         }
517         return dser;
518     }
519
520      /**
521      * Allows the destination class to be set so that downstream
522      * deserializers like ArrayDeserializer can pick it up when
523      * deserializing its components using getDeserializerForClass
524      * @param destClass is the Class of the component to be deserialized
525      */

526     public void setDestinationClass(Class JavaDoc destClass) {
527         this.destClass = destClass;
528     }
529
530     /**
531      * Allows the destination class to be retrieved so that downstream
532      * deserializers like ArrayDeserializer can pick it up when
533      * deserializing its components using getDeserializerForClass
534      * @return the Class of the component to be deserialized
535      */

536     public Class JavaDoc getDestinationClass() {
537         return destClass;
538     }
539
540     /**
541      * Convenience method to get the Deserializer for a specific
542      * xmlType.
543      * @param xmlType is QName for a type to deserialize
544      * @return Deserializer
545      */

546     public final Deserializer getDeserializerForType(QName JavaDoc xmlType) {
547         return getDeserializer(null, xmlType);
548     }
549
550     /**
551      * Get the TypeMapping for this DeserializationContext
552      */

553     public TypeMapping getTypeMapping()
554     {
555         if (msgContext == null || msgContext.getTypeMappingRegistry() == null) {
556             return (TypeMapping) new org.apache.axis.encoding.TypeMappingRegistryImpl().getTypeMapping(
557                     null);
558         }
559         TypeMappingRegistry tmr = msgContext.getTypeMappingRegistry();
560         return (TypeMapping) tmr.getTypeMapping(getEncodingStyle());
561     }
562
563     /**
564      * Get the TypeMappingRegistry we're using.
565      * @return TypeMapping or null
566      */

567     public TypeMappingRegistry getTypeMappingRegistry() {
568         return msgContext.getTypeMappingRegistry();
569     }
570
571     /**
572      * Get the MessageElement for the indicated id (where id is the #value of an href)
573      * If the MessageElement has not been processed, the MessageElement will
574      * be returned. If the MessageElement has been processed, the actual object
575      * value is stored with the id and this routine will return null.
576      * @param id is the value of an href attribute
577      * @return MessageElement or null
578      */

579     public MessageElement getElementByID(String JavaDoc id)
580     {
581         if((idMap != null)) {
582             IDResolver resolver = (IDResolver)idMap.get(id);
583             if(resolver != null) {
584                 Object JavaDoc ret = resolver.getReferencedObject(id);
585                 if (ret instanceof MessageElement)
586                     return (MessageElement)ret;
587             }
588         }
589
590         return null;
591     }
592
593     /**
594      * Gets the MessageElement or actual Object value associated with the href value.
595      * The return of a MessageElement indicates that the referenced element has
596      * not been processed. If it is not a MessageElement, the Object is the
597      * actual deserialized value.
598      * In addition, this method is invoked to get Object values via Attachments.
599      * @param href is the value of an href attribute (or an Attachment id)
600      * @return MessageElement other Object or null
601      */

602     public Object JavaDoc getObjectByRef(String JavaDoc href) {
603         Object JavaDoc ret= null;
604         if(href != null){
605             if((idMap != null)){
606                 IDResolver resolver = (IDResolver)idMap.get(href);
607                 if(resolver != null)
608                    ret = resolver.getReferencedObject(href);
609             }
610             if( null == ret && !href.startsWith("#")){
611                 //Could this be an attachment?
612
Message msg= null;
613                 if(null != (msg=msgContext.getCurrentMessage())){
614                     Attachments attch= null;
615                     if( null != (attch= msg.getAttachmentsImpl())){
616                         try{
617                         ret= attch.getAttachmentByReference(href);
618                         }catch(AxisFault e){
619                             throw new RuntimeException JavaDoc(e.toString() + JavaUtils.stackToString(e));
620                         }
621                     }
622                 }
623             }
624         }
625
626         return ret;
627     }
628
629     /**
630      * Add the object associated with this id (where id is the value of an id= attribute,
631      * i.e. it does not start with #).
632      * This routine is called to associate the deserialized object
633      * with the id specified on the XML element.
634      * @param id (id name without the #)
635      * @param obj is the deserialized object for this id.
636      */

637     public void addObjectById(String JavaDoc id, Object JavaDoc obj)
638     {
639         // The resolver uses the href syntax as the key.
640
String JavaDoc idStr = '#' + id;
641         if ((idMap == null) || (id == null))
642             return ;
643
644         IDResolver resolver = (IDResolver)idMap.get(idStr);
645         if (resolver == null)
646             return ;
647
648         resolver.addReferencedObject(idStr, obj);
649         return;
650     }
651
652     /**
653      * During deserialization, an element with an HREF=#id<int>
654      * may be encountered before the element defining id=id<int> is
655      * read. In these cases, the getObjectByRef method above will
656      * return null. The deserializer is placed in a table keyed
657      * by href (a fixup table). After the element id is processed,
658      * the deserializer is informed of the value so that it can
659      * update its target(s) with the value.
660      * @param href (#id syntax)
661      * @param dser is the deserializer of the element
662      */

663     public void registerFixup(String JavaDoc href, Deserializer dser)
664     {
665         if (fixups == null)
666             fixups = new HashMap JavaDoc();
667
668         Deserializer prev = (Deserializer) fixups.put(href, dser);
669
670         // There could already be a deserializer in the fixup list
671
// for this href. If so, the easiest way to get all of the
672
// targets updated is to move the previous deserializers
673
// targets to dser.
674
if (prev != null && prev != dser) {
675             dser.moveValueTargets(prev);
676             if (dser.getDefaultType() == null) {
677                 dser.setDefaultType(prev.getDefaultType());
678             }
679         }
680     }
681
682     /**
683      * Register the MessageElement with this id (where id is id= form without the #)
684      * This routine is called when the MessageElement with an id is read.
685      * If there is a Deserializer in our fixup list (described above),
686      * the 'fixup' deserializer is given to the MessageElement. When the
687      * MessageElement is completed, the 'fixup' deserializer is informed and
688      * it can set its targets.
689      * @param id (id name without the #)
690      * @param elem is the MessageElement
691      */

692     public void registerElementByID(String JavaDoc id, MessageElement elem)
693     {
694         if (localIDs == null)
695             localIDs = new LocalIDResolver();
696
697         String JavaDoc absID = '#' + id;
698
699         localIDs.addReferencedObject(absID, elem);
700
701         registerResolverForID(absID, localIDs);
702
703         if (fixups != null) {
704             Deserializer dser = (Deserializer)fixups.get(absID);
705             if (dser != null) {
706                 elem.setFixupDeserializer(dser);
707             }
708         }
709     }
710
711     /**
712      * Each id can have its own kind of resolver. This registers a
713      * resolver for the id.
714      */

715     public void registerResolverForID(String JavaDoc id, IDResolver resolver)
716     {
717         if ((id == null) || (resolver == null)) {
718             // ??? Throw nullPointerException?
719
return;
720         }
721
722         if (idMap == null)
723             idMap = new HashMap JavaDoc();
724
725         idMap.put(id, resolver);
726     }
727
728     /**
729      * Return true if any ids are being tracked by this DeserializationContext
730      *
731      * @return true if any ides are being tracked by this DeserializationContext
732      */

733     public boolean hasElementsByID()
734     {
735         return idMap == null ? false : idMap.size() > 0;
736     }
737
738     /**
739      * Get the current position in the record.
740      */

741     public int getCurrentRecordPos()
742     {
743         if (recorder == null) return -1;
744         return recorder.getLength() - 1;
745     }
746
747     /**
748      * Get the start of the mapping position
749      */

750     public int getStartOfMappingsPos()
751     {
752         if (startOfMappingsPos == -1) {
753             return getCurrentRecordPos() + 1;
754         }
755
756         return startOfMappingsPos;
757     }
758
759     /**
760      * Push the MessageElement into the recorder
761      */

762     public void pushNewElement(MessageElement elem)
763     {
764         if (debugEnabled) {
765             log.debug("Pushing element " + elem.getName());
766         }
767
768         if (!doneParsing && (recorder != null)) {
769             recorder.newElement(elem);
770         }
771
772         try {
773             if(curElement != null)
774                 elem.setParentElement(curElement);
775         } catch (Exception JavaDoc e) {
776             /*
777              * The only checked exception that may be thrown from setParent
778              * occurs if the parent already has an explicit object value,
779              * which should never occur during deserialization.
780              */

781             log.fatal(Messages.getMessage("exception00"), e);
782         }
783         curElement = elem;
784
785         if (elem.getRecorder() != recorder)
786             recorder = elem.getRecorder();
787     }
788
789     /****************************************************************
790      * Management of sub-handlers (deserializers)
791      */

792
793     public void pushElementHandler(SOAPHandler handler)
794     {
795         if (debugEnabled) {
796             log.debug(Messages.getMessage("pushHandler00", "" + handler));
797         }
798
799         if (topHandler != null) pushedDownHandlers.add(topHandler);
800         topHandler = handler;
801     }
802
803     /** Replace the handler at the top of the stack.
804      *
805      * This is only used when we have a placeholder Deserializer
806      * for a referenced object which doesn't know its type until we
807      * hit the referent.
808      */

809     public void replaceElementHandler(SOAPHandler handler)
810     {
811         topHandler = handler;
812     }
813
814     public SOAPHandler popElementHandler()
815     {
816         SOAPHandler result = topHandler;
817
818         int size = pushedDownHandlers.size();
819         if (size > 0) {
820             topHandler = (SOAPHandler) pushedDownHandlers.remove(size-1);
821         } else {
822             topHandler = null;
823         }
824
825         if (debugEnabled) {
826             if (result == null) {
827                 log.debug(Messages.getMessage("popHandler00", "(null)"));
828             } else {
829                 log.debug(Messages.getMessage("popHandler00", "" + result));
830             }
831         }
832
833         return result;
834     }
835
836     boolean processingRef = false;
837     public void setProcessingRef(boolean ref) {
838         processingRef = ref;
839     }
840     public boolean isProcessingRef() {
841         return processingRef;
842     }
843
844     /****************************************************************
845      * SAX event handlers
846      */

847     public void startDocument() throws SAXException JavaDoc {
848         // Should never receive this in the midst of a parse.
849
if (!doneParsing && (recorder != null))
850             recorder.startDocument();
851     }
852
853     /**
854      * endDocument is invoked at the end of the document.
855      */

856     public void endDocument() throws SAXException JavaDoc {
857         if (debugEnabled) {
858             log.debug("Enter: DeserializationContext::endDocument()");
859         }
860         if (!doneParsing && (recorder != null))
861             recorder.endDocument();
862
863         doneParsing = true;
864
865         if (debugEnabled) {
866             log.debug("Exit: DeserializationContext::endDocument()");
867         }
868     }
869     /**
870      * Return if done parsing document.
871      */

872     public boolean isDoneParsing() {return doneParsing;}
873
874     /** Record the current set of prefix mappings in the nsMappings table.
875      *
876      * !!! We probably want to have this mapping be associated with the
877      * MessageElements, since they may potentially need access to them
878      * long after the end of the prefix mapping here. (example:
879      * when we need to record a long string of events scanning forward
880      * in the document to find an element with a particular ID.)
881      */

882     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
883         throws SAXException JavaDoc
884     {
885         if (debugEnabled) {
886             log.debug("Enter: DeserializationContext::startPrefixMapping(" + prefix + ", " + uri + ")");
887         }
888
889         if (!doneParsing && (recorder != null)) {
890             recorder.startPrefixMapping(prefix, uri);
891         }
892
893         if (startOfMappingsPos == -1) {
894             namespaces.push();
895             startOfMappingsPos = getCurrentRecordPos();
896         }
897
898         if (prefix != null) {
899             namespaces.add(uri, prefix);
900         } else {
901             namespaces.add(uri, "");
902         }
903
904         if (!haveSeenSchemaNS && msgContext != null) {
905             // If we haven't yet seen a schema namespace, check if this
906
// is one. If so, set the SchemaVersion appropriately.
907
// Hopefully the schema def is on the outermost element so we
908
// get this over with quickly.
909
for (int i = 0; !haveSeenSchemaNS && i < schemaVersions.length;
910                  i++) {
911                 SchemaVersion schemaVersion = schemaVersions[i];
912                 if (uri.equals(schemaVersion.getXsdURI()) ||
913                         uri.equals(schemaVersion.getXsiURI())) {
914                     msgContext.setSchemaVersion(schemaVersion);
915                     haveSeenSchemaNS = true;
916                 }
917             }
918         }
919
920         if (topHandler != null) {
921             topHandler.startPrefixMapping(prefix, uri);
922         }
923
924         if (debugEnabled) {
925             log.debug("Exit: DeserializationContext::startPrefixMapping()");
926         }
927     }
928
929     public void endPrefixMapping(String JavaDoc prefix)
930         throws SAXException JavaDoc
931     {
932         if (debugEnabled) {
933             log.debug("Enter: DeserializationContext::endPrefixMapping(" + prefix + ")");
934         }
935
936         if (!doneParsing && (recorder != null)) {
937             recorder.endPrefixMapping(prefix);
938         }
939
940         if (topHandler != null) {
941             topHandler.endPrefixMapping(prefix);
942         }
943
944         if (debugEnabled) {
945             log.debug("Exit: DeserializationContext::endPrefixMapping()");
946         }
947     }
948
949     public void setDocumentLocator(Locator JavaDoc locator)
950     {
951         if (!doneParsing && (recorder != null)) {
952             recorder.setDocumentLocator(locator);
953         }
954         this.locator = locator;
955     }
956
957     public Locator JavaDoc getDocumentLocator() {
958         return locator;
959     }
960
961     public void characters(char[] p1, int p2, int p3) throws SAXException JavaDoc {
962         if (!doneParsing && (recorder != null)) {
963             recorder.characters(p1, p2, p3);
964         }
965         if (topHandler != null) {
966             topHandler.characters(p1, p2, p3);
967         }
968     }
969
970     public void ignorableWhitespace(char[] p1, int p2, int p3) throws SAXException JavaDoc {
971         if (!doneParsing && (recorder != null)) {
972             recorder.ignorableWhitespace(p1, p2, p3);
973         }
974         if (topHandler != null) {
975             topHandler.ignorableWhitespace(p1, p2, p3);
976         }
977     }
978
979     public void processingInstruction(String JavaDoc p1, String JavaDoc p2) throws SAXException JavaDoc {
980         // must throw an error since SOAP 1.1 doesn't allow
981
// processing instructions anywhere in the message
982
throw new SAXException JavaDoc(Messages.getMessage("noInstructions00"));
983     }
984
985     public void skippedEntity(String JavaDoc p1) throws SAXException JavaDoc {
986         if (!doneParsing && (recorder != null)) {
987             recorder.skippedEntity(p1);
988         }
989         topHandler.skippedEntity(p1);
990     }
991
992     /**
993      * startElement is called when an element is read. This is the big work-horse.
994      *
995      * This guy also handles monitoring the recording depth if we're recording
996      * (so we know when to stop).
997      */

998     public void startElement(String JavaDoc namespace, String JavaDoc localName,
999                              String JavaDoc qName, Attributes attributes)
1000        throws SAXException JavaDoc
1001    {
1002        if (debugEnabled) {
1003            log.debug("Enter: DeserializationContext::startElement(" + namespace + ", " + localName + ")");
1004        }
1005
1006        if (attributes == null || attributes.getLength() == 0) {
1007            attributes = NullAttributes.singleton;
1008        } else {
1009            attributes = new AttributesImpl JavaDoc(attributes);
1010
1011            SOAPConstants soapConstants = getSOAPConstants();
1012            if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
1013                if (attributes.getValue(soapConstants.getAttrHref()) != null &&
1014                    attributes.getValue(Constants.ATTR_ID) != null) {
1015
1016                    AxisFault fault = new AxisFault(Constants.FAULT_SOAP12_SENDER,
1017                        null, Messages.getMessage("noIDandHREFonSameElement"), null, null, null);
1018
1019                    throw new SAXException JavaDoc(fault);
1020
1021                }
1022            }
1023
1024        }
1025
1026        SOAPHandler nextHandler = null;
1027
1028        String JavaDoc prefix = "";
1029        int idx = qName.indexOf(':');
1030        if (idx > 0) {
1031            prefix = qName.substring(0, idx);
1032        }
1033
1034        if (topHandler != null) {
1035            nextHandler = topHandler.onStartChild(namespace,
1036                                                       localName,
1037                                                       prefix,
1038                                                       attributes,
1039                                                       this);
1040        }
1041
1042        if (nextHandler == null) {
1043            nextHandler = new SOAPHandler();
1044        }
1045
1046        pushElementHandler(nextHandler);
1047
1048        nextHandler.startElement(namespace, localName, prefix,
1049                                 attributes, this);
1050
1051        if (!doneParsing && (recorder != null)) {
1052            recorder.startElement(namespace, localName, qName,
1053                                  attributes);
1054            if (!doneParsing) {
1055                curElement.setContentsIndex(recorder.getLength());
1056            }
1057        }
1058
1059        if (startOfMappingsPos != -1) {
1060            startOfMappingsPos = -1;
1061        } else {
1062            // Push an empty frame if there are no mappings
1063
namespaces.push();
1064        }
1065
1066        if (debugEnabled) {
1067            log.debug("Exit: DeserializationContext::startElement()");
1068        }
1069    }
1070
1071    /**
1072     * endElement is called at the end tag of an element
1073     */

1074    public void endElement(String JavaDoc namespace, String JavaDoc localName, String JavaDoc qName)
1075        throws SAXException JavaDoc
1076    {
1077        if (debugEnabled) {
1078            log.debug("Enter: DeserializationContext::endElement(" + namespace + ", " + localName + ")");
1079        }
1080
1081        if (!doneParsing && (recorder != null)) {
1082            recorder.endElement(namespace, localName, qName);
1083        }
1084
1085        try {
1086            SOAPHandler handler = popElementHandler();
1087            handler.endElement(namespace, localName, this);
1088
1089            if (topHandler != null) {
1090                topHandler.onEndChild(namespace, localName, this);
1091            } else {
1092                // We should be done!
1093
}
1094
1095        } finally {
1096            if (curElement != null) {
1097                curElement = (MessageElement)curElement.getParentElement();
1098            }
1099
1100            namespaces.pop();
1101
1102            if (debugEnabled) {
1103                String JavaDoc name = curElement != null ?
1104                        curElement.getClass().getName() + ":" +
1105                        curElement.getName() : null;
1106                log.debug("Popped element stack to " + name);
1107                log.debug("Exit: DeserializationContext::endElement()");
1108            }
1109        }
1110    }
1111
1112    /**
1113     * This class is used to map ID's to an actual value Object or Message
1114     */

1115    private static class LocalIDResolver implements IDResolver
1116    {
1117        HashMap JavaDoc idMap = null;
1118
1119        /**
1120         * Add object associated with id
1121         */

1122        public void addReferencedObject(String JavaDoc id, Object JavaDoc referent)
1123        {
1124            if (idMap == null) {
1125                idMap = new HashMap JavaDoc();
1126            }
1127
1128            idMap.put(id, referent);
1129        }
1130
1131        /**
1132         * Get object referenced by href
1133         */

1134        public Object JavaDoc getReferencedObject(String JavaDoc href)
1135        {
1136            if ((idMap == null) || (href == null)) {
1137                return null;
1138            }
1139            return idMap.get(href);
1140        }
1141    }
1142
1143    public void startDTD(java.lang.String JavaDoc name,
1144                     java.lang.String JavaDoc publicId,
1145                     java.lang.String JavaDoc systemId)
1146              throws SAXException JavaDoc
1147    {
1148        /* It is possible for a malicious user to send us bad stuff in
1149           the <!DOCTYPE ../> tag that will cause a denial of service
1150           Example:
1151           <?xml version="1.0" ?>
1152            <!DOCTYPE foobar [
1153                <!ENTITY x0 "hello">
1154                <!ENTITY x1 "&x0;&x0;">
1155                <!ENTITY x2 "&x1;&x1;">
1156                  ...
1157                <!ENTITY x99 "&x98;&x98;">
1158                <!ENTITY x100 "&x99;&x99;">
1159            ]>
1160        */

1161        throw new SAXException JavaDoc(Messages.getMessage("noInstructions00"));
1162        /* if (recorder != null)
1163            recorder.startDTD(name, publicId, systemId);
1164        */

1165    }
1166
1167    public void endDTD()
1168            throws SAXException JavaDoc
1169    {
1170        if (recorder != null)
1171            recorder.endDTD();
1172    }
1173
1174    public void startEntity(java.lang.String JavaDoc name)
1175                 throws SAXException JavaDoc
1176    {
1177        if (recorder != null)
1178            recorder.startEntity(name);
1179    }
1180
1181    public void endEntity(java.lang.String JavaDoc name)
1182               throws SAXException JavaDoc
1183    {
1184        if (recorder != null)
1185            recorder.endEntity(name);
1186    }
1187
1188    public void startCDATA()
1189                throws SAXException JavaDoc
1190    {
1191        if (recorder != null)
1192            recorder.startCDATA();
1193    }
1194
1195    public void endCDATA()
1196              throws SAXException JavaDoc
1197    {
1198        if (recorder != null)
1199            recorder.endCDATA();
1200    }
1201
1202    public void comment(char[] ch,
1203                    int start,
1204                    int length)
1205             throws SAXException JavaDoc
1206    {
1207        if (recorder != null)
1208            recorder.comment(ch, start, length);
1209    }
1210
1211    public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
1212    {
1213        return XMLUtils.getEmptyInputSource();
1214    }
1215
1216
1217    /** We only need one instance of this dummy handler to set into the parsers. */
1218    private static final NullLexicalHandler nullLexicalHandler = new NullLexicalHandler();
1219
1220    /**
1221     * It is illegal to set the lexical-handler property to null. To facilitate
1222     * discarding the heavily loaded instance of DeserializationContextImpl from
1223     * the SAXParser instance that is kept in the Stack maintained by XMLUtils
1224     * we use this class.
1225     */

1226    private static class NullLexicalHandler implements LexicalHandler JavaDoc {
1227        public void startDTD(String JavaDoc arg0, String JavaDoc arg1, String JavaDoc arg2) throws SAXException JavaDoc {}
1228        public void endDTD() throws SAXException JavaDoc {}
1229        public void startEntity(String JavaDoc arg0) throws SAXException JavaDoc {}
1230        public void endEntity(String JavaDoc arg0) throws SAXException JavaDoc {}
1231        public void startCDATA() throws SAXException JavaDoc {}
1232        public void endCDATA() throws SAXException JavaDoc {}
1233        public void comment(char[] arg0, int arg1, int arg2) throws SAXException JavaDoc {}
1234    }
1235}
1236
1237
Popular Tags