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      * @return Object of proper type, or null if no mapping could be found.
851      */

852     public Object JavaDoc getObjectValue(Class JavaDoc cls) throws Exception JavaDoc {
853         if (objectValue == null) {
854             objectValue = getValueAsType(getType(), cls);
855         }
856         return objectValue;
857     }
858
859     /**
860      * Sets value of this node to an Object.
861      * A serializer needs to be registered for this object class for proper
862      * operation.
863      * <p>
864      * Note that this method will log an error and no-op if there are
865      * any children in the MessageElement or if the MessageElement was
866      * constructed from XML.
867      * @param newValue node's value or null.
868      */

869     public void setObjectValue(Object JavaDoc newValue) throws SOAPException JavaDoc {
870         if (children != null && !children.isEmpty()) {
871             SOAPException JavaDoc exc = new SOAPException JavaDoc(Messages.getMessage("childPresent"));
872             log.error(Messages.getMessage("childPresent"), exc);
873             throw exc;
874         }
875         if (textRep != null) {
876             SOAPException JavaDoc exc = new SOAPException JavaDoc(Messages.getMessage("xmlPresent"));
877             log.error(Messages.getMessage("xmlPresent"), exc);
878             throw exc;
879         }
880         this.objectValue = newValue;
881     }
882
883     public Object JavaDoc getValueAsType(QName JavaDoc type) throws Exception JavaDoc
884     {
885         return getValueAsType(type, null);
886     }
887
888     /**
889      * This is deserialization logic mixed in to our element class.
890      * It is only valid we have a deserializer, which means that we were created
891      * using {@link MessageElement#MessageElement(String, String, String, org.xml.sax.Attributes, org.apache.axis.encoding.DeserializationContext)}
892      * @param type type to look up a deserializer for.
893      * @param cls class to use for looking up the deserializer. This takes precedence over the type field.
894      * @return the value of the deserializer
895      * @throws Exception
896      */

897     public Object JavaDoc getValueAsType(QName JavaDoc type, Class JavaDoc cls) throws Exception JavaDoc
898     {
899         if (context == null) {
900             throw new Exception JavaDoc(Messages.getMessage("noContext00"));
901         }
902
903         Deserializer dser = null;
904         if (cls == null) {
905             dser = context.getDeserializerForType(type);
906         } else {
907             dser = context.getDeserializerForClass(cls);
908         }
909         if (dser == null) {
910             throw new Exception JavaDoc(Messages.getMessage("noDeser00", "" + type));
911         }
912
913         boolean oldVal = context.isDoneParsing();
914         context.deserializing(true);
915         context.pushElementHandler(new EnvelopeHandler((SOAPHandler)dser));
916
917         publishToHandler((org.xml.sax.ContentHandler JavaDoc) context);
918
919         context.deserializing(oldVal);
920
921         return dser.getValue();
922     }
923
924     /**
925      * class that represents a qname in a the qNameAttrs vector.
926      */

927     protected static class QNameAttr {
928         public QName JavaDoc name;
929         public QName JavaDoc value;
930     }
931
932     /**
933      * add an attribute to the qname vector. This is a separate vector from the
934      * main attribute list.
935      * @param namespace
936      * @param localName
937      * @param value
938      */

939
940     public void addAttribute(String JavaDoc namespace, String JavaDoc localName,
941                              QName JavaDoc value)
942     {
943         if (qNameAttrs == null) {
944             qNameAttrs = new Vector JavaDoc();
945         }
946
947         QNameAttr attr = new QNameAttr();
948         attr.name = new QName JavaDoc(namespace, localName);
949         attr.value = value;
950
951         qNameAttrs.addElement(attr);
952         // !!! Add attribute to attributes!
953
}
954
955     /**
956      * add a normal CDATA/text attribute.
957      * There is no check whether or not the attribute already exists.
958      * @param namespace namespace URI
959      * @param localName local anme
960      * @param value value
961      */

962     public void addAttribute(String JavaDoc namespace, String JavaDoc localName,
963                              String JavaDoc value)
964     {
965         AttributesImpl JavaDoc attributes = makeAttributesEditable();
966         attributes.addAttribute(namespace, localName, "", "CDATA",
967                                 value);
968     }
969
970     /**
971      * add an attribute.
972      * Note that the prefix is not added to our mapping list.
973      * Also, there is no check whether or not the attribute already exists.
974      * @param attrPrefix prefix.
975      * @param namespace namespace URI
976      * @param localName
977      * @param value
978      */

979     public void addAttribute(String JavaDoc attrPrefix, String JavaDoc namespace, String JavaDoc localName,
980                              String JavaDoc value)
981     {
982         AttributesImpl JavaDoc attributes = makeAttributesEditable();
983         String JavaDoc attrName = localName;
984         if (attrPrefix != null && attrPrefix.length() > 0) {
985             attrName = attrPrefix + ":" + localName;
986         }
987         attributes.addAttribute(namespace, localName, attrName, "CDATA",
988                                 value);
989     }
990
991     /**
992      * Set an attribute, adding the attribute if it isn't already present
993      * in this element, and changing the value if it is. Passing null as the
994      * value will cause any pre-existing attribute by this name to go away.
995      */

996     public void setAttribute(String JavaDoc namespace, String JavaDoc localName,
997                              String JavaDoc value)
998     {
999         AttributesImpl JavaDoc attributes = makeAttributesEditable();
1000
1001        int idx = attributes.getIndex(namespace, localName);
1002        if (idx > -1) {
1003            // Got it, so replace it's value.
1004
if (value != null) {
1005                attributes.setValue(idx, value);
1006            } else {
1007                attributes.removeAttribute(idx);
1008            }
1009            return;
1010        }
1011
1012        addAttribute(namespace, localName, value);
1013    }
1014
1015    /**
1016     * get the value of an attribute
1017     * @param localName
1018     * @return the value or null
1019     */

1020    public String JavaDoc getAttributeValue(String JavaDoc localName)
1021    {
1022        if (attributes == null) {
1023           return null;
1024        }
1025        return attributes.getValue(localName);
1026    }
1027
1028    /**
1029     * bind a a new soap envelope. sets the dirty bit.
1030     * @param env
1031     */

1032    public void setEnvelope(SOAPEnvelope env)
1033    {
1034        env.setDirty(true);
1035        message = env;
1036    }
1037
1038    /**
1039     * get our current envelope
1040     * @return envelope or null.
1041     */

1042    public SOAPEnvelope getEnvelope()
1043    {
1044        return message;
1045    }
1046
1047    /**
1048     * get the 'real' element -will follow hrefs.
1049     * @return the message element or null if there is a href to something
1050     * that is not a MessageElemeent.
1051     */

1052    public MessageElement getRealElement()
1053    {
1054        if (href == null) {
1055            return this;
1056        }
1057
1058        Object JavaDoc obj = context.getObjectByRef(href);
1059        if (obj == null) {
1060            return null;
1061        }
1062
1063        if (!(obj instanceof MessageElement)) {
1064            return null;
1065        }
1066
1067        return (MessageElement) obj;
1068    }
1069
1070    /**
1071     * get the message element as a document.
1072     * This serializes the element to a string and then parses it.
1073     * @see #getAsString()
1074     * @return
1075     * @throws Exception
1076     */

1077    public Document JavaDoc getAsDocument() throws Exception JavaDoc
1078    {
1079        String JavaDoc elementString = getAsString();
1080
1081        Reader JavaDoc reader = new StringReader JavaDoc(elementString);
1082        Document JavaDoc doc = XMLUtils.newDocument(new InputSource JavaDoc(reader));
1083        if (doc == null) {
1084            throw new Exception JavaDoc(
1085                    Messages.getMessage("noDoc00", elementString));
1086        }
1087        return doc;
1088    }
1089
1090    /**
1091     * get the message element as a string.
1092     * This is not a cheap operation, as we have to serialise the
1093     * entire message element to the current context, then
1094     * convert it to a string.
1095     * Nor is it cached; repeated calls repeat the operation.
1096     * @return an XML fragment in a string.
1097     * @throws Exception if anything went wrong
1098     */

1099    public String JavaDoc getAsString() throws Exception JavaDoc {
1100        SerializationContext serializeContext = null;
1101        StringWriter JavaDoc writer = new StringWriter JavaDoc();
1102        MessageContext msgContext;
1103        if (context != null) {
1104            msgContext = context.getMessageContext();
1105        } else {
1106            msgContext = MessageContext.getCurrentContext();
1107        }
1108        serializeContext = new SerializationContext(writer, msgContext);
1109        serializeContext.setSendDecl(false);
1110        setDirty(false);
1111        output(serializeContext);
1112        writer.close();
1113
1114        return writer.getBuffer().toString();
1115    }
1116
1117    /**
1118     * create a DOM from the message element, by
1119     * serializing and deserializing the element
1120     * @see #getAsString()
1121     * @see #getAsDocument()
1122     * @return the root document element of the element
1123     * @throws Exception
1124     */

1125    public Element JavaDoc getAsDOM() throws Exception JavaDoc
1126    {
1127        return getAsDocument().getDocumentElement();
1128    }
1129
1130    /**
1131     * replay the sax events to a handler
1132     * @param handler
1133     * @throws SAXException
1134     */

1135    public void publishToHandler(ContentHandler JavaDoc handler) throws SAXException JavaDoc
1136    {
1137        if (recorder == null) {
1138            throw new SAXException JavaDoc(Messages.getMessage("noRecorder00"));
1139        }
1140
1141        recorder.replay(startEventIndex, endEventIndex, handler);
1142    }
1143
1144    /**
1145     * replay the sax events to a SAX content handles
1146     * @param handler
1147     * @throws SAXException
1148     */

1149    public void publishContents(ContentHandler JavaDoc handler) throws SAXException JavaDoc
1150    {
1151        if (recorder == null) {
1152            throw new SAXException JavaDoc(Messages.getMessage("noRecorder00"));
1153        }
1154
1155        recorder.replay(startContentsIndex, endEventIndex-1, handler);
1156    }
1157
1158    /** This is the public output() method, which will always simply use
1159     * the recorded SAX stream for this element if it is available. If
1160     * not, this method calls outputImpl() to allow subclasses and
1161     * programmatically created messages to serialize themselves.
1162     *
1163     * @param outputContext the SerializationContext we will write to.
1164     */

1165    public final void output(SerializationContext outputContext) throws Exception JavaDoc
1166    {
1167        if ((recorder != null) && (!_isDirty)) {
1168            recorder.replay(startEventIndex,
1169                            endEventIndex,
1170                            new SAXOutputter(outputContext));
1171            return;
1172        }
1173
1174        // Turn QName attributes into strings
1175
if (qNameAttrs != null) {
1176            for (int i = 0; i < qNameAttrs.size(); i++) {
1177                QNameAttr attr = (QNameAttr)qNameAttrs.get(i);
1178                QName JavaDoc attrName = attr.name;
1179                setAttribute(attrName.getNamespaceURI(),
1180                             attrName.getLocalPart(),
1181                             outputContext.qName2String(attr.value));
1182            }
1183        }
1184
1185        /**
1186         * Write the encoding style attribute IF it's different from
1187         * whatever encoding style is in scope....
1188         */

1189        if (encodingStyle != null) {
1190            MessageContext mc = outputContext.getMessageContext();
1191            SOAPConstants soapConstants = (mc != null) ?
1192                                            mc.getSOAPConstants() :
1193                                            SOAPConstants.SOAP11_CONSTANTS;
1194            if (parent == null) {
1195                // don't emit an encoding style if its "" (literal)
1196
if (!"".equals(encodingStyle)) {
1197                    setAttribute(soapConstants.getEnvelopeURI(),
1198                                 Constants.ATTR_ENCODING_STYLE,
1199                                 encodingStyle);
1200                }
1201            } else if (!encodingStyle.equals(((MessageElement)parent).getEncodingStyle())) {
1202                setAttribute(soapConstants.getEnvelopeURI(),
1203                             Constants.ATTR_ENCODING_STYLE,
1204                             encodingStyle);
1205            }
1206        }
1207
1208        outputImpl(outputContext);
1209    }
1210
1211    /**
1212     * override point -output to a serialization context.
1213     * @param outputContext destination.
1214     * @throws Exception if something went wrong.
1215     */

1216    protected void outputImpl(SerializationContext outputContext) throws Exception JavaDoc
1217    {
1218        if (textRep != null) {
1219            boolean oldPretty = outputContext.getPretty();
1220            outputContext.setPretty(false);
1221            if (textRep instanceof CDATASection JavaDoc) {
1222                outputContext.writeString("<![CDATA[");
1223                outputContext.writeString(textRep.getData());
1224                outputContext.writeString("]]>");
1225            } else if (textRep instanceof Comment JavaDoc) {
1226                outputContext.writeString("<!--");
1227                outputContext.writeString(textRep.getData());
1228                outputContext.writeString("-->");
1229            } else if (textRep instanceof Text) {
1230                outputContext.writeSafeString(textRep.getData());
1231            }
1232            outputContext.setPretty(oldPretty);
1233            return;
1234        }
1235
1236        if (prefix != null)
1237            outputContext.registerPrefixForURI(prefix, namespaceURI);
1238
1239        if (namespaces != null) {
1240            for (Iterator JavaDoc i = namespaces.iterator(); i.hasNext();) {
1241                Mapping mapping = (Mapping) i.next();
1242                outputContext.registerPrefixForURI(mapping.getPrefix(), mapping.getNamespaceURI());
1243            }
1244        }
1245
1246        if (objectValue != null) {
1247            outputContext.serialize(new QName JavaDoc(namespaceURI, name),
1248                              attributes,
1249                              objectValue);
1250            return;
1251        }
1252
1253        outputContext.startElement(new QName JavaDoc(namespaceURI, name), attributes);
1254        if (children != null) {
1255            for (Iterator JavaDoc it = children.iterator(); it.hasNext();) {
1256                ((NodeImpl)it.next()).output(outputContext);
1257            }
1258        }
1259        outputContext.endElement();
1260    }
1261
1262    /**
1263     * Generate a string representation by serializing our contents
1264     * This is not a lightweight operation, and is repeated whenever
1265     * you call this method.
1266     * If the serialization fails, an error is logged and the classic
1267     * {@link Object#toString()} operation invoked instead.
1268     * @return a string representing the class
1269     */

1270    public String JavaDoc toString() {
1271        try {
1272            return getAsString();
1273        }
1274        catch( Exception JavaDoc exp ) {
1275            //couldn't turn to a string.
1276
//log it
1277
log.error(Messages.getMessage("exception00"), exp);
1278            //then hand off to our superclass, which is probably object
1279
return super.toString();
1280        }
1281    }
1282
1283    /**
1284     * add a new namespace/prefix mapping
1285     * @param map new mapping to add
1286     * @todo: this code does not verify that the mapping does not exist already; it
1287     * is possible to create duplicate mappings.
1288     */

1289    public void addMapping(Mapping map) {
1290        if (namespaces == null) {
1291            namespaces = new ArrayList JavaDoc();
1292        }
1293        namespaces.add(map);
1294    }
1295
1296    // JAXM SOAPElement methods...
1297

1298    /**
1299     * add the child element
1300     * @param childName uri, prefix and local name of the element to add
1301     * @return the child element
1302     * @throws SOAPException
1303     * @see javax.xml.soap.SOAPElement#addChildElement(javax.xml.soap.Name)
1304     */

1305    public SOAPElement JavaDoc addChildElement(Name JavaDoc childName) throws SOAPException JavaDoc {
1306        MessageElement child = new MessageElement(childName.getLocalName(),
1307                                                  childName.getPrefix(),
1308                                                  childName.getURI());
1309        addChild(child);
1310        return child;
1311    }
1312
1313    /**
1314     * add a child element in the message element's own namespace
1315     * @param localName
1316     * @return the child element
1317     * @throws SOAPException
1318     * @see javax.xml.soap.SOAPElement#addChildElement(String)
1319     */

1320    public SOAPElement JavaDoc addChildElement(String JavaDoc localName) throws SOAPException JavaDoc {
1321        // Inherit parent's namespace
1322
MessageElement child = new MessageElement(getNamespaceURI(),
1323                                                  localName);
1324        addChild(child);
1325        return child;
1326    }
1327
1328    /**
1329     * add a child element
1330     * @param localName
1331     * @param prefixName
1332     * @return the child element
1333     * @throws SOAPException
1334     * @see javax.xml.soap.SOAPElement#addChildElement(String, String)
1335     */

1336    public SOAPElement JavaDoc addChildElement(String JavaDoc localName,
1337                                       String JavaDoc prefixName) throws SOAPException JavaDoc {
1338        MessageElement child = new MessageElement(getNamespaceURI(prefixName),
1339                                                  localName);
1340        child.setPrefix(prefixName);
1341        addChild(child);
1342        return child;
1343    }
1344
1345    /**
1346     * add a child element
1347     * @param localName
1348     * @param childPrefix
1349     * @param uri
1350     * @return the child element
1351     * @throws SOAPException
1352     * @see javax.xml.soap.SOAPElement#addChildElement(String, String, String)
1353     */

1354    public SOAPElement JavaDoc addChildElement(String JavaDoc localName,
1355                                       String JavaDoc childPrefix,
1356                                       String JavaDoc uri) throws SOAPException JavaDoc {
1357        MessageElement child = new MessageElement(uri, localName);
1358        child.setPrefix(childPrefix);
1359        child.addNamespaceDeclaration(childPrefix, uri);
1360        addChild(child);
1361        return child;
1362    }
1363
1364    /**
1365     * The added child must be an instance of MessageElement rather than
1366     * an abitrary SOAPElement otherwise a (wrapped) ClassCastException
1367     * will be thrown.
1368     * @see javax.xml.soap.SOAPElement#addChildElement(javax.xml.soap.SOAPElement)
1369     */

1370    public SOAPElement JavaDoc addChildElement(SOAPElement JavaDoc element)
1371        throws SOAPException JavaDoc {
1372        try {
1373            addChild((MessageElement)element);
1374            setDirty(true);
1375            return element;
1376        } catch (ClassCastException JavaDoc e) {
1377            throw new SOAPException JavaDoc(e);
1378        }
1379    }
1380
1381    /**
1382     * add a text node to the document.
1383     * @return ourselves
1384     * @see javax.xml.soap.SOAPElement#addTextNode(String)
1385     */

1386    public SOAPElement JavaDoc addTextNode(String JavaDoc s) throws SOAPException JavaDoc {
1387        try {
1388            Text text = getOwnerDocument().createTextNode(s);
1389            ((org.apache.axis.message.Text)text).setParentElement(this);
1390            return this;
1391        } catch (java.lang.IncompatibleClassChangeError JavaDoc e) {
1392            Text text = new org.apache.axis.message.Text(s);
1393            this.appendChild(text);
1394            return this;
1395        } catch (ClassCastException JavaDoc e) {
1396            throw new SOAPException JavaDoc(e);
1397        }
1398    }
1399
1400    /**
1401     * add a new attribute
1402     * @param attrName name of the attribute
1403     * @param value a string value
1404     * @return ourselves
1405     * @throws SOAPException
1406     * @see javax.xml.soap.SOAPElement#addAttribute(javax.xml.soap.Name, String)
1407     */

1408    public SOAPElement JavaDoc addAttribute(Name JavaDoc attrName, String JavaDoc value)
1409        throws SOAPException JavaDoc {
1410        try {
1411            addAttribute(attrName.getPrefix(), attrName.getURI(), attrName.getLocalName(), value);
1412        } catch (RuntimeException JavaDoc t) {
1413            throw new SOAPException JavaDoc(t);
1414        }
1415        return this;
1416    }
1417
1418    /**
1419     * create a {@link Mapping} mapping and add to our namespace list.
1420     * @param prefix
1421     * @param uri
1422     * @return
1423     * @throws SOAPException for any {@link RuntimeException} caught
1424     * @todo for some reason this logic catches all rutime exceptions and
1425     * rethrows them as SOAPExceptions. This is unusual behavio, and should
1426     * be looked at closely.
1427     * @see javax.xml.soap.SOAPElement#addNamespaceDeclaration(String, String)
1428     */

1429    public SOAPElement JavaDoc addNamespaceDeclaration(String JavaDoc prefix,
1430                                               String JavaDoc uri)
1431        throws SOAPException JavaDoc {
1432        try {
1433            Mapping map = new Mapping(uri, prefix);
1434            addMapping(map);
1435        } catch (RuntimeException JavaDoc t) {
1436            //TODO: why is this here? Nowhere else do we turn runtimes into SOAPExceptions.
1437
throw new SOAPException JavaDoc(t);
1438        }
1439        return this;
1440    }
1441
1442    /**
1443     * Get the value of an attribute whose namespace and local name are described.
1444     * @param attrName qualified name of the attribute
1445     * @return the attribute or null if there was no match
1446     * @see SOAPElement#getAttributeValue(javax.xml.soap.Name)
1447     */

1448    public String JavaDoc getAttributeValue(Name JavaDoc attrName) {
1449        return attributes.getValue(attrName.getURI(), attrName.getLocalName());
1450    }
1451
1452    /**
1453     * Get an interator to all the attributes of the node.
1454     * The iterator is over a static snapshot of the node names; if attributes
1455     * are added or deleted during the iteration, this iterator will be not
1456     * be updated to follow the changes.
1457     * @return an iterator of the attributes.
1458     * @see javax.xml.soap.SOAPElement#getAllAttributes()
1459     */

1460    public Iterator JavaDoc getAllAttributes() {
1461        int num = attributes.getLength();
1462        Vector JavaDoc attrs = new Vector JavaDoc(num);
1463        for (int i = 0; i < num; i++) {
1464            String JavaDoc q = attributes.getQName(i);
1465            String JavaDoc prefix = "";
1466            if (q != null) {
1467                int idx = q.indexOf(":");
1468                if (idx > 0) {
1469                    prefix = q.substring(0, idx);
1470                } else {
1471                    prefix= "";
1472                }
1473            }
1474
1475            attrs.add(new PrefixedQName(attributes.getURI(i),
1476                                        attributes.getLocalName(i),
1477                                        prefix));
1478        }
1479        return attrs.iterator();
1480    }
1481
1482    // getNamespaceURI implemented above
1483

1484    /**
1485     * get an iterator of the prefixes. The iterator
1486     * does not get updated in response to changes in the namespace list.
1487     * @return an iterator over a vector of prefixes
1488     * @see javax.xml.soap.SOAPElement#getNamespacePrefixes()
1489     */

1490    public Iterator JavaDoc getNamespacePrefixes() {
1491        Vector JavaDoc prefixes = new Vector JavaDoc();
1492        for (int i = 0; namespaces != null && i < namespaces.size(); i++) {
1493            prefixes.add(((Mapping)namespaces.get(i)).getPrefix());
1494        }
1495        return prefixes.iterator();
1496    }
1497
1498    /**
1499     * get the full name of the element
1500     * @return
1501     * @see javax.xml.soap.SOAPElement#getElementName()
1502     */

1503    public Name JavaDoc getElementName() {
1504        return new PrefixedQName(getNamespaceURI(), getName(), getPrefix());
1505    }
1506
1507    /**
1508     * remove an element
1509     * @param attrName name of the element
1510     * @return true if the attribute was found and removed.
1511     * @see javax.xml.soap.SOAPElement#removeAttribute(javax.xml.soap.Name)
1512     */

1513    public boolean removeAttribute(Name JavaDoc attrName) {
1514        AttributesImpl JavaDoc attributes = makeAttributesEditable();
1515        boolean removed = false;
1516
1517        for (int i = 0; i < attributes.getLength() && !removed; i++) {
1518            if (attributes.getURI(i).equals(attrName.getURI()) &&
1519                attributes.getLocalName(i).equals(attrName.getLocalName())) {
1520                attributes.removeAttribute(i);
1521                removed = true;
1522            }
1523        }
1524        return removed;
1525    }
1526
1527    /**
1528     * remove a namespace declaration.
1529     * @param namespacePrefix
1530     * @return true if the prefix was found and removed.
1531     * @see javax.xml.soap.SOAPElement#removeNamespaceDeclaration(String)
1532     */

1533    public boolean removeNamespaceDeclaration(String JavaDoc namespacePrefix) {
1534        makeAttributesEditable();
1535        boolean removed = false;
1536
1537        for (int i = 0; namespaces != null && i < namespaces.size() && !removed; i++) {
1538            if (((Mapping)namespaces.get(i)).getPrefix().equals(namespacePrefix)) {
1539                namespaces.remove(i);
1540                removed = true;
1541            }
1542        }
1543        return removed;
1544    }
1545
1546    /**
1547     * get an iterator over the children
1548     * This iterator <i>may</i> get confused if changes are made to the
1549     * children while the iteration is in progress.
1550     * @return an iterator over child elements.
1551     * @see javax.xml.soap.SOAPElement#getChildElements()
1552     */

1553    public Iterator JavaDoc getChildElements() {
1554        initializeChildren();
1555        return children.iterator();
1556    }
1557
1558    /**
1559     * Convenience method to get the first matching child for a given QName.
1560     *
1561     * @param qname
1562     * @return child element or null
1563     * @see javax.xml.soap.SOAPElement#getChildElements()
1564     */

1565    public MessageElement getChildElement(QName JavaDoc qname) {
1566        if (children != null) {
1567            for (Iterator JavaDoc i = children.iterator(); i.hasNext();) {
1568                MessageElement child = (MessageElement) i.next();
1569                if (child.getQName().equals(qname))
1570                    return child;
1571            }
1572        }
1573        return null;
1574    }
1575
1576    /**
1577     * get an iterator over child elements
1578     * @param qname namespace/element name of parts to find.
1579     * This iterator is not (currently) susceptible to change in the element
1580     * list during its lifetime, though changes in the contents of the elements
1581     * are picked up.
1582     * @return an iterator.
1583     */

1584    public Iterator JavaDoc getChildElements(QName JavaDoc qname) {
1585        initializeChildren();
1586        int num = children.size();
1587        Vector JavaDoc c = new Vector JavaDoc(num);
1588        for (int i = 0; i < num; i++) {
1589            MessageElement child = (MessageElement)children.get(i);
1590            Name JavaDoc cname = child.getElementName();
1591            if (cname.getURI().equals(qname.getNamespaceURI()) &&
1592                cname.getLocalName().equals(qname.getLocalPart())) {
1593                c.add(child);
1594            }
1595        }
1596        return c.iterator();
1597    }
1598
1599    /**
1600     * get an iterator over child elements
1601     * @param childName namespace/element name of parts to find.
1602     * This iterator is not (currently) susceptible to change in the element
1603     * list during its lifetime, though changes in the contents of the elements
1604     * are picked up.
1605     * @return an iterator.
1606     * @see javax.xml.soap.SOAPElement#getChildElements(javax.xml.soap.Name)
1607     */

1608    public Iterator JavaDoc getChildElements(Name JavaDoc childName) {
1609        return getChildElements(new QName JavaDoc(childName.getURI(), childName.getLocalName()));
1610    }
1611
1612    //DOM methods
1613

1614    /**
1615     * @see org.w3c.dom.Element#getTagName()
1616     * @return the name of the element
1617     */

1618    public String JavaDoc getTagName() {
1619        return prefix == null ? name : prefix + ":" + name;
1620    }
1621
1622    /**
1623     * remove a named attribute.
1624     * @see org.w3c.dom.Element#removeAttribute(String)
1625     * @param attrName name of the attributes
1626     * @throws DOMException
1627     */

1628    public void removeAttribute(String JavaDoc attrName) throws DOMException JavaDoc {
1629        AttributesImpl JavaDoc impl = (AttributesImpl JavaDoc)attributes;
1630        int index = impl.getIndex(attrName);
1631        if(index >= 0){
1632            AttributesImpl JavaDoc newAttrs = new AttributesImpl JavaDoc();
1633            // copy except the removed attribute
1634
for(int i = 0; i < impl.getLength(); i++){ // shift after removal
1635
if(i != index){
1636                    String JavaDoc uri = impl.getURI(i);
1637                    String JavaDoc local = impl.getLocalName(i);
1638                    String JavaDoc qname = impl.getQName(i);
1639                    String JavaDoc type = impl.getType(i);
1640                    String JavaDoc value = impl.getValue(i);
1641                    newAttrs.addAttribute(uri,local,qname,type,value);
1642                }
1643            }
1644            // replace it
1645
attributes = newAttrs;
1646        }
1647    }
1648
1649    /**
1650     * test for an attribute existing
1651     * @param attrName name of attribute (or null)
1652     * @return true if it exists
1653     * Note that the behaviour for a null parameter (returns false) is not guaranteed in future
1654     * @see org.w3c.dom.Element#hasAttribute(String)
1655     */

1656    public boolean hasAttribute(String JavaDoc attrName) {
1657        if(attrName == null) // Do I have to send an exception?
1658
attrName = "";
1659
1660        for(int i = 0; i < attributes.getLength(); i++){
1661            if(attrName.equals(attributes.getQName(i)))
1662                return true;
1663        }
1664        return false;
1665    }
1666
1667    /**
1668     * get an attribute by name
1669     * @param attrName of attribute
1670     * @return the attribute value or null
1671     * @see org.w3c.dom.Element#getAttribute(String)
1672     */

1673    public String JavaDoc getAttribute(String JavaDoc attrName) {
1674        return attributes.getValue(attrName);
1675    }
1676
1677    /**
1678     * Remove an attribute. If the removed
1679     * attribute has a default value it is immediately replaced. The
1680     * replacing attribute has the same namespace URI and local name, as
1681     * well as the original prefix.
1682     * If there is no matching attribute, the operation is a no-op.
1683     * @see org.w3c.dom.Element#removeAttributeNS(String, String)
1684     * @param namespace namespace of attr
1685     * @param localName local name
1686     * @throws DOMException
1687     */

1688    public void removeAttributeNS(String JavaDoc namespace, String JavaDoc localName) throws DOMException JavaDoc {
1689        makeAttributesEditable();
1690        Name JavaDoc name = new PrefixedQName(namespace, localName, null);
1691        removeAttribute(name);
1692    }
1693
1694    /**
1695     * set or update an attribute.
1696     * @see org.w3c.dom.Element#setAttribute(String, String)
1697     * @param name attribute name
1698     * @param value attribute value
1699     * @throws DOMException
1700     */

1701    public void setAttribute(String JavaDoc name, String JavaDoc value) throws DOMException JavaDoc {
1702        AttributesImpl JavaDoc impl = makeAttributesEditable();
1703        int index = impl.getIndex(name);
1704        if (index < 0) { // not found
1705
String JavaDoc uri = "";
1706            String JavaDoc localname = name;
1707            String JavaDoc qname = name;
1708            String JavaDoc type = "CDDATA";
1709            impl.addAttribute(uri, localname, qname, type, value);
1710        } else { // found
1711
impl.setLocalName(index, value);
1712        }
1713    }
1714
1715    /**
1716     * Test for an attribute
1717     * @see org.w3c.dom.Element#hasAttributeNS(String, String)
1718     * @param namespace
1719     * @param localName
1720     * @return
1721     */

1722    public boolean hasAttributeNS(String JavaDoc namespace, String JavaDoc localName) {
1723        if (namespace == null) {
1724            namespace = "";
1725        }
1726        if (localName == null) // Do I have to send an exception? or just return false
1727
{
1728            localName = "";
1729        }
1730
1731        for(int i = 0; i < attributes.getLength(); i++){
1732            if( namespace.equals(attributes.getURI(i))
1733                    && localName.equals(attributes.getLocalName(i)))
1734                return true;
1735        }
1736        return false;
1737    }
1738
1739    /**
1740     * This unimplemented operation is meand to return an attribute as a node
1741     * @see org.w3c.dom.Element#getAttributeNode(String)
1742     * @param attrName
1743     * @return null, always.
1744     * @todo Fix this for SAAJ 1.2 Implementation. marked as deprecated to warn people
1745     * it is broken
1746     * @deprecated this is not implemented
1747     */

1748    public Attr JavaDoc getAttributeNode(String JavaDoc attrName) {
1749        return null;
1750    }
1751
1752    /**
1753     * remove a an attribue
1754     * @param oldAttr
1755     * @return oldAttr
1756     * @throws DOMException
1757     */

1758    public Attr JavaDoc removeAttributeNode(Attr JavaDoc oldAttr) throws DOMException JavaDoc {
1759        makeAttributesEditable();
1760        Name JavaDoc name = new PrefixedQName(oldAttr.getNamespaceURI(), oldAttr.getLocalName(), oldAttr.getPrefix());
1761        removeAttribute(name);
1762        return oldAttr;
1763    }
1764
1765    /**
1766     * set the attribute node.
1767     * @see org.w3c.dom.Element#setAttributeNode(org.w3c.dom.Attr)
1768     * @param newAttr
1769     * @return newAttr
1770     * @throws DOMException
1771     * @deprecated this is not implemented
1772     * @todo implement
1773     */

1774    public Attr JavaDoc setAttributeNode(Attr JavaDoc newAttr) throws DOMException JavaDoc {
1775        return newAttr;
1776    }
1777
1778    /**
1779     * set an attribute as a node
1780     * @see org.w3c.dom.Element#setAttributeNodeNS(org.w3c.dom.Attr)
1781     * @todo implement properly.
1782     * @param newAttr
1783     * @return null
1784     * @throws DOMException
1785     */

1786    public Attr JavaDoc setAttributeNodeNS(Attr JavaDoc newAttr) throws DOMException JavaDoc {
1787        //attributes.
1788
AttributesImpl JavaDoc attributes = makeAttributesEditable();
1789        // how to convert to DOM ATTR
1790
attributes.addAttribute(newAttr.getNamespaceURI(),
1791                newAttr.getLocalName(),
1792                newAttr.getLocalName(),
1793                "CDATA",
1794                newAttr.getValue());
1795        return null;
1796    }
1797
1798    /**
1799     * @see org.w3c.dom.Element#getElementsByTagName(String)
1800     * @param tagName tag to look for.
1801     * @return a list of elements
1802     */

1803    public NodeList JavaDoc getElementsByTagName(String JavaDoc tagName) {
1804        NodeListImpl nodelist = new NodeListImpl();
1805        for (int i = 0; children != null && i < children.size(); i++) {
1806            if (children.get(i) instanceof Node JavaDoc) {
1807                Node JavaDoc el = (Node JavaDoc)children.get(i);
1808                if (el.getLocalName() != null && el.getLocalName()
1809                                .equals(tagName))
1810                    nodelist.addNode(el);
1811                if (el instanceof Element JavaDoc) {
1812                    NodeList JavaDoc grandchildren =
1813                            ((Element JavaDoc)el).getElementsByTagName(tagName);
1814                    for (int j = 0; j < grandchildren.getLength(); j++) {
1815                        nodelist.addNode(grandchildren.item(j));
1816                    }
1817                }
1818            }
1819        }
1820        return nodelist;
1821    }
1822    
1823    /**
1824     * get the attribute with namespace/local name match.
1825     * @see org.w3c.dom.Element#getAttributeNS(String, String)
1826     * @param namespaceURI namespace
1827     * @param localName name
1828     * @return string value or null if not found
1829     * @todo: this could be refactored to use getAttributeValue()
1830     */

1831    public String JavaDoc getAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
1832        if(namespaceURI == null) {
1833            namespaceURI = "";
1834        }
1835        for (int i = 0; i < attributes.getLength(); i++) {
1836            if (attributes.getURI(i).equals(namespaceURI) &&
1837                    attributes.getLocalName(i).equals(localName)) {
1838                return attributes.getValue(i);
1839            }
1840        }
1841        return null;
1842    }
1843
1844    /**
1845     * set an attribute or alter an existing one
1846     * @see org.w3c.dom.Element#setAttributeNS(String, String, String)
1847     * @param namespaceURI namepsace
1848     * @param qualifiedName qualified name of the attribue
1849     * @param value value
1850     * @throws DOMException
1851     */

1852    public void setAttributeNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName,
1853                               String JavaDoc value)
1854        throws DOMException JavaDoc
1855    {
1856        AttributesImpl JavaDoc attributes = makeAttributesEditable();
1857        String JavaDoc localName = qualifiedName.substring(qualifiedName.indexOf(":")+1, qualifiedName.length());
1858
1859        if (namespaceURI == null) {
1860            namespaceURI = "intentionalNullURI";
1861        }
1862        attributes.addAttribute(namespaceURI,
1863                localName,
1864                qualifiedName,
1865                "CDATA",
1866                value);
1867    }
1868
1869    /**
1870     * @see org.w3c.dom.Element#getAttributeNS(String, String)
1871     * @deprecated not implemented!
1872     * @param namespace namespace
1873     * @param localName local name
1874     * @return null
1875     */

1876    public Attr JavaDoc getAttributeNodeNS(String JavaDoc namespace, String JavaDoc localName) {
1877        return null; //TODO: Fix this for SAAJ 1.2 Implementation
1878
}
1879
1880    /**
1881     * @see org.w3c.dom.Element#getElementsByTagNameNS(String, String)
1882     * @param namespace namespace
1883     * @param localName local name of element
1884     * @return (potentially empty) list of elements that match the (namespace,localname) tuple
1885     */

1886    public NodeList JavaDoc getElementsByTagNameNS(String JavaDoc namespace,
1887                                           String JavaDoc localName)
1888    {
1889        return getElementsNS(this,namespace,localName);
1890    }
1891
1892    /**
1893     * helper method for recusively getting the element that has namespace URI and localname
1894     * @param parentElement parent element
1895     * @param namespace namespace
1896     * @param localName local name of element
1897     * @return (potentially empty) list of elements that match the (namespace,localname) tuple
1898     */

1899    protected NodeList JavaDoc getElementsNS(org.w3c.dom.Element JavaDoc parentElement,
1900                                     String JavaDoc namespace, String JavaDoc localName)
1901    {
1902        NodeList JavaDoc children = parentElement.getChildNodes();
1903        NodeListImpl matches = new NodeListImpl();
1904
1905        for (int i = 0; i < children.getLength(); i++) {
1906            if (children.item(i) instanceof Text) {
1907                continue;
1908            }
1909            Element JavaDoc child = (Element JavaDoc) children.item(i);
1910            if (namespace.equals(child.getNamespaceURI()) &&
1911                    localName.equals(child.getLocalName())) {
1912                matches.addNode(child);
1913            }
1914            // search the grand-children.
1915
matches.addNodeList(child.getElementsByTagNameNS(namespace,
1916                    localName));
1917        }
1918        return matches;
1919    }
1920
1921    /**
1922     * get a child node
1923     * @param index index value
1924     * @return child or null for out of range value
1925     * @see org.w3c.dom.NodeList#item(int)
1926     */

1927    public Node JavaDoc item(int index) {
1928        if (children != null && children.size() > index) {
1929            return (Node JavaDoc) children.get(index);
1930        } else {
1931            return null;
1932        }
1933    }
1934
1935    /**
1936     * The number of nodes in the list. The range of valid child node indices
1937     * is 0 to <code>length-1</code> inclusive.
1938     * @return number of children
1939     * @since SAAJ 1.2 : Nodelist Interface
1940     * @see org.w3c.dom.NodeList#getLength()
1941     */

1942    public int getLength()
1943    {
1944        return (children == null) ? 0 : children.size();
1945    }
1946
1947    // setEncodingStyle implemented above
1948

1949    // getEncodingStyle() implemented above
1950

1951    protected MessageElement findElement(Vector JavaDoc vec, String JavaDoc namespace,
1952                               String JavaDoc localPart)
1953    {
1954        if (vec.isEmpty()) {
1955            return null;
1956        }
1957
1958        QName JavaDoc qname = new QName JavaDoc(namespace, localPart);
1959        Enumeration JavaDoc e = vec.elements();
1960        MessageElement element;
1961        while (e.hasMoreElements()) {
1962            element = (MessageElement) e.nextElement();
1963            if (element.getQName().equals(qname)) {
1964                return element;
1965            }
1966        }
1967
1968        return null;
1969    }
1970
1971    /**
1972     * equality test. Does a string match of the two message elements,
1973     * so is fairly brute force.
1974     * @see #toString()
1975     * @param obj
1976     * @return
1977     */

1978    public boolean equals(Object JavaDoc obj)
1979    {
1980        if (obj == null || !(obj instanceof MessageElement)) {
1981            return false;
1982        }
1983        if (this == obj) {
1984            return true;
1985        }
1986        if (!this.getLocalName().equals(((MessageElement) obj).getLocalName())) {
1987            return false;
1988        }
1989        return toString().equals(obj.toString());
1990    }
1991
1992    /**
1993     * recursively copy.
1994     * Note that this does not reset many of our fields, and must be used with caution.
1995     * @param element
1996     */

1997    private void copyNode(org.w3c.dom.Node JavaDoc element) {
1998        copyNode(this, element);
1999    }
2000
2001    /**
2002     * recursive copy
2003     * @param dest element to copy into
2004     * @param source child element
2005     */

2006    private void copyNode(MessageElement dest, org.w3c.dom.Node JavaDoc source)
2007    {
2008        dest.setPrefix(source.getPrefix());
2009        if(source.getLocalName() != null) {
2010            dest.setQName(new QName JavaDoc(source.getNamespaceURI(), source.getLocalName()));
2011        }
2012        else
2013        {
2014            dest.setQName(new QName JavaDoc(source.getNamespaceURI(), source.getNodeName()));
2015        }
2016
2017        NamedNodeMap JavaDoc attrs = source.getAttributes();
2018        for(int i = 0; i < attrs.getLength(); i++){
2019            Node JavaDoc att = attrs.item(i);
2020        if (att.getNamespaceURI() != null &&
2021                att.getPrefix() != null &&
2022                att.getNamespaceURI().equals(Constants.NS_URI_XMLNS) &&
2023                "xmlns".equals(att.getPrefix())) {
2024                Mapping map = new Mapping(att.getNodeValue(), att.getLocalName());
2025                dest.addMapping(map);
2026            }
2027            if(att.getLocalName() != null) {
2028                dest.addAttribute(att.getPrefix(),
2029                        (att.getNamespaceURI() != null ? att.getNamespaceURI() : ""),
2030                        att.getLocalName(),
2031                        att.getNodeValue());
2032            } else if (att.getNodeName() != null) {
2033                dest.addAttribute(att.getPrefix(),
2034                        (att.getNamespaceURI() != null ? att.getNamespaceURI() : ""),
2035                        att.getNodeName(),
2036                        att.getNodeValue());
2037            }
2038        }
2039
2040        NodeList JavaDoc children = source.getChildNodes();
2041        for(int i = 0; i < children.getLength(); i++){
2042            Node JavaDoc child = children.item(i);
2043            if(child.getNodeType()==TEXT_NODE ||
2044               child.getNodeType()==CDATA_SECTION_NODE ||
2045               child.getNodeType()==COMMENT_NODE ) {
2046                org.apache.axis.message.Text childElement =
2047                    new org.apache.axis.message.Text((CharacterData JavaDoc)child);
2048                dest.appendChild(childElement);
2049            } else {
2050                MessageElement childElement = new MessageElement();
2051                dest.appendChild(childElement);
2052                copyNode(childElement, child);
2053            }
2054        }
2055    }
2056
2057    /**
2058     * Get the value of the doc as a string.
2059     * This uses {@link #getAsDOM()} so is a heavyweight operation.
2060     * @return the value of any child node, or null if there is no node/something went
2061     * wrong during serialization. If the first child is text, the return value
2062     * is the text itself.
2063     * @see javax.xml.soap.Node#getValue() ;
2064     */

2065    public String JavaDoc getValue() {
2066        /*--- Fix for AXIS-1817
2067        if ((recorder != null) && (!_isDirty)) {
2068            StringWriter writer = new StringWriter();
2069            TextSerializationContext outputContext =
2070                new TextSerializationContext(writer);
2071            try {
2072                recorder.replay(startEventIndex,
2073                                endEventIndex,
2074                                new SAXOutputter(outputContext));
2075            } catch (Exception t) {
2076                log.debug("getValue()", t);
2077                return null;
2078            }
2079            String value = writer.toString();
2080            return (value.length() == 0) ? null : value;
2081        }
2082        ---*/

2083
2084        if (textRep != null) {
2085            // weird case: error?
2086
return textRep.getNodeValue();
2087        }
2088
2089        if (objectValue != null) {
2090            return getValueDOM();
2091        }
2092
2093        for (Iterator JavaDoc i = getChildElements(); i.hasNext(); ) {
2094            NodeImpl n = (NodeImpl) i.next();
2095            if (n instanceof Text) {
2096                return ((Text)n).getNodeValue();
2097            }
2098        }
2099
2100        return null;
2101    }
2102
2103    protected String JavaDoc getValueDOM() {
2104        try {
2105            Element JavaDoc element = getAsDOM();
2106            if (element.hasChildNodes()) {
2107                Node JavaDoc node = element.getFirstChild();
2108                if (node.getNodeType() == Node.TEXT_NODE) {
2109                    return node.getNodeValue();
2110                }
2111            }
2112        } catch (Exception JavaDoc t) {
2113            log.debug("getValue()", t);
2114        }
2115        return null;
2116    }
2117
2118    public void setValue( String JavaDoc value )
2119    {
2120        // if possible, get objectValue in sync with Node value
2121
if (children==null) {
2122            try {
2123                setObjectValue(value);
2124            } catch ( SOAPException JavaDoc soape ) {
2125                log.debug("setValue()", soape);
2126            }
2127        }
2128        super.setValue(value);
2129    }
2130
2131    public Document JavaDoc getOwnerDocument() {
2132        Document JavaDoc doc = null;
2133        if (context != null && context.getEnvelope() != null &&
2134                context.getEnvelope().getOwnerDocument() != null) {
2135            doc = context.getEnvelope().getOwnerDocument();
2136        }
2137        if(doc == null) {
2138            doc = super.getOwnerDocument();
2139        }
2140        if (doc == null) {
2141            doc = new SOAPDocumentImpl(null);
2142        }
2143        return doc;
2144    }
2145}
2146
Popular Tags