KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > message > MessageElement


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 package org.apache.axis.message;
18
19 import org.apache.axis.AxisFault;
20 import org.apache.axis.Constants;
21 import org.apache.axis.MessageContext;
22 import org.apache.axis.components.logger.LogFactory;
23 import org.apache.axis.encoding.DeserializationContext;
24 import org.apache.axis.encoding.Deserializer;
25 import org.apache.axis.encoding.SerializationContext;
26 import org.apache.axis.encoding.TextSerializationContext;
27 import org.apache.axis.constants.Style;
28 import org.apache.axis.soap.SOAPConstants;
29 import org.apache.axis.utils.Mapping;
30 import org.apache.axis.utils.Messages;
31 import org.apache.axis.utils.XMLUtils;
32 import org.apache.commons.logging.Log;
33 import org.w3c.dom.Attr JavaDoc;
34 import org.w3c.dom.CDATASection JavaDoc;
35 import org.w3c.dom.CharacterData JavaDoc;
36 import org.w3c.dom.Comment JavaDoc;
37 import org.w3c.dom.DOMException JavaDoc;
38 import org.w3c.dom.Document JavaDoc;
39 import org.w3c.dom.Element JavaDoc;
40 import org.w3c.dom.Node JavaDoc;
41 import org.w3c.dom.NodeList JavaDoc;
42 import org.w3c.dom.Text JavaDoc;
43 import org.w3c.dom.NamedNodeMap JavaDoc;
44 import org.xml.sax.Attributes JavaDoc;
45 import org.xml.sax.ContentHandler JavaDoc;
46 import org.xml.sax.InputSource JavaDoc;
47 import org.xml.sax.SAXException JavaDoc;
48 import org.xml.sax.helpers.AttributesImpl JavaDoc;
49
50 import javax.xml.namespace.QName JavaDoc;
51 import javax.xml.rpc.encoding.TypeMapping JavaDoc;
52 import javax.xml.soap.Name JavaDoc;
53 import javax.xml.soap.SOAPElement JavaDoc;
54 import javax.xml.soap.SOAPException JavaDoc;
55 import javax.xml.parsers.ParserConfigurationException JavaDoc;
56 import java.io.Reader JavaDoc;
57 import java.io.Serializable JavaDoc;
58 import java.io.StringReader JavaDoc;
59 import java.io.StringWriter JavaDoc;
60 import java.util.ArrayList JavaDoc;
61 import java.util.Enumeration JavaDoc;
62 import java.util.Iterator JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.Vector JavaDoc;
65
66 /**
67  * MessageElement is the base type of nodes of the SOAP message parse tree.
68  *
69  * Note: it was made Serializable to help users of Apache SOAP who had
70  * exploited the serializability of the DOM tree to migrate to Axis.
71  * @todo implement the NodeList methods properly, with tests.
72  */

73 public class MessageElement extends NodeImpl implements SOAPElement JavaDoc,
74         Serializable JavaDoc,
75         org.w3c.dom.NodeList JavaDoc, // ADD Nodelist Interfaces for SAAJ 1.2
76
Cloneable JavaDoc
77 {
78     protected static Log log =
79         LogFactory.getLog(MessageElement.class.getName());
80
81     private static final Mapping enc11Mapping =
82             new Mapping(Constants.URI_SOAP11_ENC,
83                         "SOAP-ENC");
84
85     private static final Mapping enc12Mapping =
86             new Mapping(Constants.URI_SOAP12_ENC,
87                         "SOAP-ENC");
88
89     protected String JavaDoc id;
90     protected String JavaDoc href;
91     protected boolean _isRoot = true;
92     protected SOAPEnvelope message = null;
93
94     protected transient DeserializationContext context;
95
96     protected transient QName JavaDoc typeQName = null;
97
98     protected Vector JavaDoc qNameAttrs = null;
99
100     // Some message representations - as recorded SAX events...
101
protected transient SAX2EventRecorder recorder = null;
102     protected int startEventIndex = 0;
103     protected int startContentsIndex = 0;
104     protected int endEventIndex = -1;
105
106     public ArrayList JavaDoc namespaces = null;
107
108     /** Our encoding style, if any */
109     protected String JavaDoc encodingStyle = null;
110
111     /** Object value, possibly supplied by subclass */
112     private Object JavaDoc objectValue = null;
113
114     /** No-arg constructor for building messages?
115      */

116     public MessageElement()
117     {
118     }
119
120     /**
121      * constructor
122      * @param namespace namespace of element
123      * @param localPart local name
124      */

125     public MessageElement(String JavaDoc namespace, String JavaDoc localPart)
126     {
127         namespaceURI = namespace;
128         name = localPart;
129     }
130
131     /**
132      * constructor. Automatically adds a namespace-prefix mapping to the mapping table
133      * @param localPart local name
134      * @param prefix prefix
135      * @param namespace namespace
136      */

137     public MessageElement(String JavaDoc localPart, String JavaDoc prefix, String JavaDoc namespace)
138     {
139         this.namespaceURI = namespace;
140         this.name = localPart;
141         this.prefix = prefix;
142         addMapping(new Mapping(namespace, prefix));
143     }
144
145     /**
146      * construct using a {@link javax.xml.soap.Name} implementation,
147      * @see #MessageElement(String, String, String)
148      * @param eltName
149      */

150     public MessageElement(Name JavaDoc eltName)
151     {
152         this(eltName.getLocalName(),eltName.getPrefix(), eltName.getURI());
153     }
154
155     /**
156      * constructor binding the internal object value field to the
157      * value parameter
158      * @param namespace namespace of the element
159      * @param localPart local name
160      * @param value value of the node
161      */

162     public MessageElement(String JavaDoc namespace, String JavaDoc localPart, Object JavaDoc value)
163     {
164         this(namespace, localPart);
165         objectValue = value;
166     }
167
168     /**
169      * constructor declaring the qualified name of the node
170      * @param name naming information
171      */

172     public MessageElement(QName JavaDoc name)
173     {
174         this(name.getNamespaceURI(), name.getLocalPart());
175     }
176
177     /**
178      * constructor declaring the qualified name of the node
179      * and its value
180      * @param name naming information
181      * @param value value of the node
182      */

183     public MessageElement(QName JavaDoc name, Object JavaDoc value)
184     {
185         this(name.getNamespaceURI(), name.getLocalPart());
186         objectValue = value;
187     }
188
189     /**
190      * create a node through a deep copy of the passed in element.
191      * @param elem name to copy from
192      */

193     public MessageElement(Element JavaDoc elem)
194     {
195         namespaceURI = elem.getNamespaceURI();
196         name = elem.getLocalName();
197         copyNode(elem);
198     }
199
200     /**
201      * construct a text element.
202      * @param text text data. This is <i>not</i> copied; it is referred to in the MessageElement.
203      */

204     public MessageElement(CharacterData JavaDoc text)
205     {
206         textRep = text;
207         namespaceURI = text.getNamespaceURI();
208         name = text.getLocalName();
209     }
210
211     /**
212      * Advanced constructor used for deserialization.
213      * <ol>
214      * <li>The context provides the mappings and Sax event recorder
215      * <li>The soap messaging style is determined from the current message context, defaulting
216      * to SOAP1.1 if there is no current context.
217      * <li>if there is an id attribute (any namespace), then the ID is registered
218      * with {@link DeserializationContext#registerElementByID(String, MessageElement)} ;a new recorder is
219      * created if needed.
220      * <li>If there is an attribute "root" in the default SOAP namespace, then it is examined
221      * to see if it marks the element as root (value=="1" or not)
222      * <li>If there is an arrayType attribute then we assume we are an array and set our
223      * {@link #typeQName} field appropriately.
224      * <li>The {@link #href} field is set if there is a relevant href value
225      * </ol>
226      *
227      * @param namespace namespace namespace of element
228      * @param localPart local name local name of element
229      * @param prefix prefix prefix of element
230      * @param attributes attributes to save as our attributes
231      * @param context deserialization context for this message element
232      * @throws AxisFault if the encoding style is not recognized/supported
233      */

234     public MessageElement(String JavaDoc namespace, String JavaDoc localPart, String JavaDoc prefix,
235                    Attributes JavaDoc attributes, DeserializationContext context)
236         throws AxisFault
237     {
238         if (log.isDebugEnabled()) {
239             log.debug(Messages.getMessage("newElem00", super.toString(),
240                                             "{" + prefix + "}" + localPart));
241             for (int i = 0; attributes != null && i < attributes.getLength(); i++) {
242                 log.debug(" " + attributes.getQName(i) + " = '" + attributes.getValue(i) + "'");
243             }
244         }
245         this.namespaceURI = namespace;
246         this.name = localPart;
247         this.prefix = prefix;
248
249         this.context = context;
250         this.startEventIndex = context.getStartOfMappingsPos();
251
252         setNSMappings(context.getCurrentNSMappings());
253
254         this.recorder = context.getRecorder();
255
256         if (attributes != null && attributes.getLength() > 0) {
257             this.attributes = attributes;
258
259             this.typeQName = context.getTypeFromAttributes(namespace,
260                                                       localPart,
261                                                       attributes);
262
263             String JavaDoc rootVal = attributes.getValue(Constants.URI_DEFAULT_SOAP_ENC, Constants.ATTR_ROOT);
264
265             if (rootVal != null) {
266                 _isRoot = "1".equals(rootVal);
267             }
268
269             id = attributes.getValue(Constants.ATTR_ID);
270             // Register this ID with the context.....
271
if (id != null) {
272                 context.registerElementByID(id, this);
273                 if (recorder == null) {
274                     recorder = new SAX2EventRecorder();
275                     context.setRecorder(recorder);
276                 }
277             }
278
279             // Set the encoding style to the attribute value. If null,
280
// we just automatically use our parent's (see getEncodingStyle)
281
MessageContext mc = context.getMessageContext();
282             SOAPConstants sc = (mc != null) ?
283                                             mc.getSOAPConstants() :
284                                             SOAPConstants.SOAP11_CONSTANTS;
285
286             href = attributes.getValue(sc.getAttrHref());
287
288             // If there's an arrayType attribute, we can pretty well guess that we're an Array???
289
if (attributes.getValue(Constants.URI_DEFAULT_SOAP_ENC, Constants.ATTR_ARRAY_TYPE) != null) {
290                 typeQName = Constants.SOAP_ARRAY;
291             }
292
293
294             encodingStyle =
295                     attributes.getValue(sc.getEncodingURI(),
296                                         Constants.ATTR_ENCODING_STYLE);
297
298             // if no-encoding style was defined, we don't define as well
299
if (Constants.URI_SOAP12_NOENC.equals(encodingStyle))
300                 encodingStyle = null;
301
302             // If we have an encoding style, and are not a MESSAGE style
303
// operation (in other words - we're going to do some data
304
// binding), AND we're SOAP 1.2, check the encoding style against
305
// the ones we've got type mappings registered for. If it isn't
306
// registered, throw a DataEncodingUnknown fault as per the
307
// SOAP 1.2 spec.
308
if (encodingStyle != null &&
309                     sc.equals(SOAPConstants.SOAP12_CONSTANTS) &&
310                     (mc.getOperationStyle() != Style.MESSAGE)) {
311                 TypeMapping JavaDoc tm = mc.getTypeMappingRegistry().
312                         getTypeMapping(encodingStyle);
313                 if (tm == null ||
314                         (tm.equals(mc.getTypeMappingRegistry().
315                                                 getDefaultTypeMapping()))) {
316                     AxisFault badEncodingFault = new AxisFault(
317                             Constants.FAULT_SOAP12_DATAENCODINGUNKNOWN,
318                             "bad encoding style", null, null);
319                     throw badEncodingFault;
320                 }
321             }
322
323         }
324     }
325
326     /**
327      * Retrieve the DeserializationContext associated with this MessageElement
328      *
329      * @return The DeserializationContext associated with this MessageElement
330      */

331     public DeserializationContext getDeserializationContext()
332     {
333         return context;
334     }
335
336     /** !!! TODO : Make sure this handles multiple targets
337      */

338     protected Deserializer fixupDeserializer;
339
340     public void setFixupDeserializer(Deserializer dser)
341     {
342         // !!! Merge targets here if already set?
343
fixupDeserializer = dser;
344     }
345
346     public Deserializer getFixupDeserializer()
347     {
348         return fixupDeserializer;
349     }
350
351     /**
352      * record the end index of the SAX recording.
353      * @param endIndex end value
354      */

355     public void setEndIndex(int endIndex)
356     {
357         endEventIndex = endIndex;
358         //context.setRecorder(null);
359
}
360
361     /**
362      * get the is-root flag
363      * @return true if the element is considered a document root.
364      */

365     public boolean isRoot() { return _isRoot; }
366
367     /**
368      * get a saved ID
369      * @return ID or null for no ID
370      */

371     public String JavaDoc getID() { return id; }
372
373     /**
374      * get a saved href
375      * @return href or null
376      */

377     public String JavaDoc getHref() { return href; }
378
379     /**
380      * get the attributes
381      * @return attributes. If this equals {@link NullAttributes.singleton} it is null
382      *
383      */

384     public Attributes JavaDoc getAttributesEx() { return attributes; }
385
386
387     /**
388      * Returns a duplicate of this node, i.e., serves as a generic copy
389      * constructor for nodes. The duplicate node has no parent; (
390      * <code>parentNode</code> is <code>null</code>.).
391      * <br>Cloning an <code>Element</code> copies all attributes and their
392      * values, including those generated by the XML processor to represent
393      * defaulted attributes, but this method does not copy any text it
394      * contains unless it is a deep clone, since the text is contained in a
395      * child <code>Text</code> node. Cloning an <code>Attribute</code>
396      * directly, as opposed to be cloned as part of an <code>Element</code>
397      * cloning operation, returns a specified attribute (
398      * <code>specified</code> is <code>true</code>). Cloning any other type
399      * of node simply returns a copy of this node.
400      * <br>Note that cloning an immutable subtree results in a mutable copy,
401      * but the children of an <code>EntityReference</code> clone are readonly
402      * . In addition, clones of unspecified <code>Attr</code> nodes are
403      * specified. And, cloning <code>Document</code>,
404      * <code>DocumentType</code>, <code>Entity</code>, and
405      * <code>Notation</code> nodes is implementation dependent.
406      *
407      * @param deep If <code>true</code>, recursively clone the subtree under
408      * the specified node; if <code>false</code>, clone only the node
409      * itself (and its attributes, if it is an <code>Element</code>).
410      * @return The duplicate node.
411      */

412     public Node JavaDoc cloneNode(boolean deep) {
413         try{
414             MessageElement clonedSelf = (MessageElement) cloning();
415
416             if(deep){
417                 if(children != null){
418                     for(int i =0; i < children.size(); i++){
419                         NodeImpl child = (NodeImpl)children.get(i);
420                         if(child != null) { // why child can be null?
421
NodeImpl clonedChild = (NodeImpl)child.cloneNode(deep); // deep == true
422
clonedChild.setParent(clonedSelf);
423                             clonedChild.setOwnerDocument(getOwnerDocument());
424                             
425                             clonedSelf.childDeepCloned( child, clonedChild );
426                         }
427                     }
428                 }
429             }
430             return clonedSelf;
431         }
432         catch(Exception JavaDoc e){
433             return null;
434         }
435     }
436
437     // Called when a child is cloned from cloneNode().
438
//
439
// This is used by sub-classes to update internal state when specific elements
440
// are cloned.
441
protected void childDeepCloned( NodeImpl oldNode, NodeImpl newNode )
442     {
443     }
444
445     /**
446      * protected clone method (not public)
447      *
448      * copied status
449      * -------------------
450      * protected String name ; Y
451      * protected String prefix ; Y
452      * protected String namespaceURI ; Y
453      * protected transient Attributes attributes Y
454      * protected String id; Y?
455      * protected String href; Y?
456      * protected boolean _isRoot = true; Y?
457      * protected SOAPEnvelope message = null; N?
458      * protected transient DeserializationContext context; Y?
459      * protected transient QName typeQName = null; Y?
460      * protected Vector qNameAttrs = null; Y?
461      * protected transient SAX2EventRecorder recorder = null; N?
462      * protected int startEventIndex = 0; N?
463      * protected int startContentsIndex = 0; N?
464      * protected int endEventIndex = -1; N?
465      * protected CharacterData textRep = null; Y?
466      * protected MessageElement parent = null; N
467      * public ArrayList namespaces = null; Y
468      * protected String encodingStyle = null; N?
469      * private Object objectValue = null; N?
470      *
471      * @return
472      * @throws CloneNotSupportedException
473      */

474     protected Object JavaDoc cloning() throws CloneNotSupportedException JavaDoc
475     {
476         try{
477             MessageElement clonedME = null;
478             clonedME = (MessageElement)this.clone();
479
480             clonedME.setName(name);
481             clonedME.setNamespaceURI(namespaceURI);
482             clonedME.setPrefix(prefix);
483
484             // new AttributesImpl will copy all data not set referencing only
485
clonedME.setAllAttributes(new AttributesImpl JavaDoc(attributes));
486             // clonedME.addNamespaceDeclaration((namespaces.clone()); // cannot do this. since we cannot access the namepace arraylist
487

488             clonedME.namespaces = new ArrayList JavaDoc();
489             if(namespaces != null){
490                 for(int i = 0; i < namespaces.size(); i++){
491                     // jeus.util.Logger.directLog( " Debug : namspace.size() = " + namespaces.size());
492
Mapping namespace = (Mapping)namespaces.get(i);
493                     clonedME.addNamespaceDeclaration(namespace.getPrefix(), namespace.getNamespaceURI()); // why exception here!!
494
}
495             }
496             clonedME.children = new ArrayList JavaDoc();
497
498             // clear parents relationship to old parent
499
clonedME.parent = null;
500             // clonedME.setObjectValue(objectValue); // how to copy this???
501
clonedME.setDirty(this._isDirty);
502             if(encodingStyle != null){
503                 clonedME.setEncodingStyle(encodingStyle);
504             }
505             return clonedME;
506         }catch(Exception JavaDoc ex){
507             return null;
508         }
509     }
510
511
512     /**
513      * set all the attributes of this instance
514      * @param attrs a new attributes list
515      */

516     public void setAllAttributes(Attributes JavaDoc attrs){
517         attributes = attrs;
518     }
519
520     /**
521      * remove all children.
522      */

523     public void detachAllChildren()
524     {
525         removeContents();
526     }
527
528     /**
529      * Obtain an Attributes collection consisting of all attributes
530      * for this MessageElement, including namespace declarations.
531      *
532      * @return Attributes collection
533      */

534     public Attributes JavaDoc getCompleteAttributes() {
535         if (namespaces == null) {
536             return attributes;
537         }
538
539         AttributesImpl JavaDoc attrs = null;
540         if (attributes == NullAttributes.singleton) {
541             attrs = new AttributesImpl JavaDoc();
542         } else {
543             attrs = new AttributesImpl JavaDoc(attributes);
544         }
545
546         for (Iterator JavaDoc iterator = namespaces.iterator(); iterator.hasNext();) {
547             Mapping mapping = (Mapping) iterator.next();
548             String JavaDoc prefix = mapping.getPrefix();
549             String JavaDoc nsURI = mapping.getNamespaceURI();
550             attrs.addAttribute(Constants.NS_URI_XMLNS, prefix,
551                                "xmlns:" + prefix, nsURI, "CDATA");
552         }
553         return attrs;
554     }
555
556     /**
557      * get the local name of this element
558      * @return name
559      */

560     public String JavaDoc getName() {
561         return name;
562     }
563
564     /**
565      * set the local part of this element's name
566      * @param name
567      */

568     public void setName(String JavaDoc name) {
569         this.name = name;
570     }
571
572     /**
573      * get the fully qualified name of this element
574      * @return a QName describing the name of thsi element
575      */

576     public QName JavaDoc getQName() {
577         return new QName JavaDoc(namespaceURI, name);
578     }
579
580     /**
581      * set the name and namespace of this element
582      * @param qName qualified name
583      */

584     public void setQName(QName JavaDoc qName) {
585         this.name = qName.getLocalPart();
586         this.namespaceURI = qName.getNamespaceURI();
587     }
588
589     /**
590      * set the namespace URI of the element
591      * @param nsURI new namespace URI
592      */

593     public void setNamespaceURI(String JavaDoc nsURI) {
594         namespaceURI = nsURI;
595     }
596
597     /**
598      * get the element's type.
599      * If we are a reference, we look up our target in the context and
600      * return (and cache) its type.
601      * @return
602      */

603     public QName JavaDoc getType() {
604         // Try to get the type from our target if we're a reference...
605
if (typeQName == null && href != null && context != null) {
606             MessageElement referent = context.getElementByID(href);
607             if (referent != null) {
608                 typeQName = referent.getType();
609             }
610         }
611         return typeQName;
612     }
613
614     /**
615      * set the element's type
616      * @param qname
617      */

618     public void setType(QName JavaDoc qname) {
619         typeQName = qname;
620     }
621
622     /**
623      * get the event recorder
624      * @return recorder or null
625      */

626     public SAX2EventRecorder getRecorder() {
627         return recorder;
628     }
629
630     /**
631      * set the event recorder
632      * @param rec
633      */

634     public void setRecorder(SAX2EventRecorder rec) {
635         recorder = rec;
636     }
637
638     /**
639      * Get the encoding style. If ours is null, walk up the hierarchy
640      * and use our parent's. Default if we're the root is "".
641      *
642      * @return the currently in-scope encoding style
643      */

644     public String JavaDoc getEncodingStyle() {
645         if (encodingStyle == null) {
646             if (parent == null) {
647                 return "";
648             }
649             return ((MessageElement) parent).getEncodingStyle();
650         }
651         return encodingStyle;
652     }
653
654     /**
655      * remove all chidlren.
656      * All SOAPExceptions which can get thrown in this process are ignored.
657      */

658     public void removeContents() {
659         // unlink
660
if (children != null) {
661             for (int i = 0; i < children.size(); i++) {
662                 try {
663                     ((NodeImpl) children.get(i)).setParent(null);
664                 } catch (SOAPException JavaDoc e) {
665                     log.debug("ignoring", e);
666                 }
667             }
668             // empty the collection
669
children.clear();
670             setDirty(true);
671         }
672     }
673
674     /**
675      * get an iterator over visible prefixes. This includes all declared in
676      * parent elements
677      * @return an iterator.
678      */

679     public Iterator JavaDoc getVisibleNamespacePrefixes() {
680         Vector JavaDoc prefixes = new Vector JavaDoc();
681
682         // Add all parents namespace definitions
683
if(parent !=null){
684             Iterator JavaDoc parentsPrefixes = ((MessageElement)parent).getVisibleNamespacePrefixes();
685             if(parentsPrefixes != null){
686                 while(parentsPrefixes.hasNext()){
687                     prefixes.add(parentsPrefixes.next());
688                 }
689             }
690         }
691         Iterator JavaDoc mine = getNamespacePrefixes();
692         if(mine != null){
693             while(mine.hasNext()){
694                 prefixes.add(mine.next());
695             }
696         }
697         return prefixes.iterator();
698     }
699
700     /**
701      * Sets the encoding style for this <CODE>SOAPElement</CODE>
702      * object to one specified. The semantics of a null value,
703      * as above in getEncodingStyle() are to just use the parent's value,
704      * but null here means set to "".
705      *
706      * @param encodingStyle a <CODE>String</CODE>
707      * giving the encoding style
708      * @throws java.lang.IllegalArgumentException if
709      * there was a problem in the encoding style being set.
710      * @see #getEncodingStyle() getEncodingStyle()
711      */

712     public void setEncodingStyle(String JavaDoc encodingStyle) throws SOAPException JavaDoc {
713         if (encodingStyle == null) {
714             encodingStyle = "";
715         }
716
717         this.encodingStyle = encodingStyle;
718
719         // Wherever we set the encoding style, map the SOAP-ENC prefix
720
// just for fun (if it's a known style)
721
if (encodingStyle.equals(Constants.URI_SOAP11_ENC)) {
722             addMapping(enc11Mapping);
723         } else if (encodingStyle.equals(Constants.URI_SOAP12_ENC)) {
724             addMapping(enc12Mapping);
725         }
726     }
727
728     /**
729      * Note that this method will log a error and no-op if there is
730      * a value (set using setObjectValue) in the MessageElement.
731      */

732     public void addChild(MessageElement el) throws SOAPException JavaDoc
733     {
734         if (objectValue != null) {
735             IllegalStateException JavaDoc exc =
736                 new IllegalStateException JavaDoc(Messages.getMessage("valuePresent"));
737             log.error(Messages.getMessage("valuePresent"), exc);
738             throw exc;
739         }
740         initializeChildren();
741         children.add(el);
742         el.parent = this;
743     }
744
745     /**
746      * get a list of children
747      * @return a list, or null if there are no children
748      */

749     public List JavaDoc getChildren()
750     {
751         return children;
752     }
753
754     /**
755      * set the index point of our content's starting in the
756      * event recording
757      * @param index index value of the first event of our recorder.
758      */

759     public void setContentsIndex(int index)
760     {
761         startContentsIndex = index;
762     }
763
764     /**
765      * set a new namespace mapping list
766      * @param namespaces
767      */

768     public void setNSMappings(ArrayList JavaDoc namespaces)
769     {
770         this.namespaces = namespaces;
771     }
772
773     /**
774      * get the prefix for a given namespace URI
775      * @param searchNamespaceURI namespace
776      * @return null for null or emtpy uri, null for no match, and the prefix iff there is a match
777      */

778     public String JavaDoc getPrefix(String JavaDoc searchNamespaceURI) {
779         if ((searchNamespaceURI == null) || ("".equals(searchNamespaceURI)))
780             return null;
781
782         if (href != null && getRealElement() != null) {
783             return getRealElement().getPrefix(searchNamespaceURI);
784         }
785
786         for (int i = 0; namespaces != null && i < namespaces.size(); i++) {
787             Mapping map = (Mapping) namespaces.get(i);
788             if (map.getNamespaceURI().equals(searchNamespaceURI)) {
789                 return map.getPrefix();
790             }
791         }
792
793         if (parent != null) {
794             return ((MessageElement) parent).getPrefix(searchNamespaceURI);
795         }
796
797         return null;
798     }
799
800     /**
801      * map from a prefix to a namespace.
802      * Will recurse <i>upward the element tree</i> until we get a match
803      * @param searchPrefix
804      * @return the prefix, or null for no match
805      */

806     public String JavaDoc getNamespaceURI(String JavaDoc searchPrefix) {
807         if (searchPrefix == null) {
808             searchPrefix = "";
809         }
810
811         if (href != null && getRealElement() != null) {
812             return getRealElement().getNamespaceURI(searchPrefix);
813         }
814
815         for (int i = 0; namespaces != null && i < namespaces.size(); i++) {
816             Mapping map = (Mapping) namespaces.get(i);
817             if (map.getPrefix().equals(searchPrefix)) {
818                 return map.getNamespaceURI();
819             }
820         }
821
822         if (parent != null) {
823             return ((MessageElement) parent).getNamespaceURI(searchPrefix);
824         }
825
826         if (log.isDebugEnabled()) {
827             log.debug(Messages.getMessage("noPrefix00", "" + this, searchPrefix));
828         }
829
830         return null;
831     }
832
833     /**
834      * Returns value of the node as an object of registered type.
835      * @return Object of proper type, or null if no mapping could be found.
836      */

837     public Object JavaDoc getObjectValue() {
838         Object JavaDoc obj = null;
839         try {
840             obj = getObjectValue(null);
841         } catch (Exception JavaDoc e) {
842             log.debug("getValue()", e);
843         }
844         return obj;
845     }
846
847     /**
848      * Returns value of the node as an object of registered type.
849      * @param cls Class that contains top level deserializer metadata
850     &n