~ubuntu-branches/debian/squeeze/axis/squeeze

« back to all changes in this revision

Viewing changes to src/org/apache/axis/message/MessageElement.java

  • Committer: Bazaar Package Importer
  • Author(s): Vladimír Lapáček
  • Date: 2006-09-06 22:31:39 UTC
  • Revision ID: james.westby@ubuntu.com-20060906223139-l7m5edxeositeppl
Tags: upstream-1.4
Import upstream version 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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;
 
34
import org.w3c.dom.CDATASection;
 
35
import org.w3c.dom.CharacterData;
 
36
import org.w3c.dom.Comment;
 
37
import org.w3c.dom.DOMException;
 
38
import org.w3c.dom.Document;
 
39
import org.w3c.dom.Element;
 
40
import org.w3c.dom.Node;
 
41
import org.w3c.dom.NodeList;
 
42
import org.w3c.dom.Text;
 
43
import org.w3c.dom.NamedNodeMap;
 
44
import org.xml.sax.Attributes;
 
45
import org.xml.sax.ContentHandler;
 
46
import org.xml.sax.InputSource;
 
47
import org.xml.sax.SAXException;
 
48
import org.xml.sax.helpers.AttributesImpl;
 
49
 
 
50
import javax.xml.namespace.QName;
 
51
import javax.xml.rpc.encoding.TypeMapping;
 
52
import javax.xml.soap.Name;
 
53
import javax.xml.soap.SOAPElement;
 
54
import javax.xml.soap.SOAPException;
 
55
import javax.xml.parsers.ParserConfigurationException;
 
56
import java.io.Reader;
 
57
import java.io.Serializable;
 
58
import java.io.StringReader;
 
59
import java.io.StringWriter;
 
60
import java.util.ArrayList;
 
61
import java.util.Enumeration;
 
62
import java.util.Iterator;
 
63
import java.util.List;
 
64
import java.util.Vector;
 
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,
 
74
        Serializable,
 
75
        org.w3c.dom.NodeList,  // ADD Nodelist Interfaces for SAAJ 1.2
 
76
        Cloneable
 
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    id;
 
90
    protected String    href;
 
91
    protected boolean   _isRoot = true;
 
92
    protected SOAPEnvelope message = null;
 
93
 
 
94
    protected transient DeserializationContext context;
 
95
 
 
96
    protected transient QName typeQName = null;
 
97
 
 
98
    protected Vector 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 namespaces = null;
 
107
 
 
108
    /** Our encoding style, if any */
 
109
    protected String encodingStyle = null;
 
110
 
 
111
    /** Object value, possibly supplied by subclass */
 
112
    private Object 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 namespace, String 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 localPart, String prefix, String 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 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 namespace, String localPart, Object 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 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 name, Object 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 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 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 namespace, String localPart, String prefix,
 
235
                   Attributes 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 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 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 getID() { return id; }
 
372
 
 
373
    /**
 
374
     * get a saved href
 
375
     * @return href or null
 
376
     */
 
377
    public String 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 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 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 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 cloning() throws CloneNotSupportedException
 
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(attributes));
 
486
            //       clonedME.addNamespaceDeclaration((namespaces.clone()); // cannot do this. since we cannot access the namepace arraylist
 
487
 
 
488
            clonedME.namespaces = new ArrayList();
 
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();
 
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 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 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 getCompleteAttributes() {
 
535
        if (namespaces == null) {
 
536
            return attributes;
 
537
        }
 
538
 
 
539
        AttributesImpl attrs = null;
 
540
        if (attributes == NullAttributes.singleton) {
 
541
            attrs = new AttributesImpl();
 
542
        } else {
 
543
            attrs = new AttributesImpl(attributes);
 
544
        }
 
545
 
 
546
        for (Iterator iterator = namespaces.iterator(); iterator.hasNext();) {
 
547
            Mapping mapping = (Mapping) iterator.next();
 
548
            String prefix = mapping.getPrefix();
 
549
            String 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 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 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 getQName() {
 
577
        return new QName(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 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 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 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 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 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 e) {
 
665
                    log.debug("ignoring", e);
 
666
                }
 
667
            }
 
668
            // empty the collection
 
669
            children.clear();
 
670
            setDirty();
 
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 getVisibleNamespacePrefixes() {
 
680
        Vector prefixes = new Vector();
 
681
 
 
682
        // Add all parents namespace definitions
 
683
        if(parent !=null){
 
684
            Iterator parentsPrefixes = ((MessageElement)parent).getVisibleNamespacePrefixes();
 
685
            if(parentsPrefixes != null){
 
686
                while(parentsPrefixes.hasNext()){
 
687
                    prefixes.add(parentsPrefixes.next());
 
688
                }
 
689
            }
 
690
        }
 
691
        Iterator 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 encodingStyle) throws SOAPException {
 
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
 
733
    {
 
734
        if (objectValue != null) {
 
735
            IllegalStateException exc =
 
736
                new IllegalStateException(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 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 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 getPrefix(String 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 getNamespaceURI(String 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 getObjectValue() {
 
838
        Object obj = null;
 
839
        try {
 
840
            obj = getObjectValue(null);
 
841
        } catch (Exception 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 getObjectValue(Class cls) throws Exception {
 
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 newValue) throws SOAPException {
 
870
        if (children != null && !children.isEmpty()) {
 
871
            SOAPException exc = new SOAPException(Messages.getMessage("childPresent"));
 
872
            log.error(Messages.getMessage("childPresent"), exc);
 
873
            throw exc;
 
874
        }
 
875
        if (textRep != null) {
 
876
            SOAPException exc = new SOAPException(Messages.getMessage("xmlPresent"));
 
877
            log.error(Messages.getMessage("xmlPresent"), exc);
 
878
            throw exc;
 
879
        }
 
880
        this.objectValue = newValue;
 
881
    }
 
882
 
 
883
    public Object getValueAsType(QName type) throws Exception
 
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 getValueAsType(QName type, Class cls) throws Exception
 
898
    {
 
899
        if (context == null) {
 
900
            throw new Exception(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(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) 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 name;
 
929
        public QName 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 namespace, String localName,
 
941
                             QName value)
 
942
    {
 
943
        if (qNameAttrs == null) {
 
944
            qNameAttrs = new Vector();
 
945
        }
 
946
 
 
947
        QNameAttr attr = new QNameAttr();
 
948
        attr.name = new QName(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 namespace, String localName,
 
963
                             String value)
 
964
    {
 
965
        AttributesImpl 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 attrPrefix, String namespace, String localName,
 
980
                             String value)
 
981
    {
 
982
        AttributesImpl attributes = makeAttributesEditable();
 
983
        String 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 namespace, String localName,
 
997
                             String value)
 
998
    {
 
999
        AttributesImpl 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 getAttributeValue(String 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();
 
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 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 getAsDocument() throws Exception
 
1078
    {
 
1079
        String elementString = getAsString();
 
1080
 
 
1081
        Reader reader = new StringReader(elementString);
 
1082
        Document doc = XMLUtils.newDocument(new InputSource(reader));
 
1083
        if (doc == null) {
 
1084
            throw new Exception(
 
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 getAsString() throws Exception {
 
1100
        SerializationContext serializeContext = null;
 
1101
        StringWriter writer = new StringWriter();
 
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 getAsDOM() throws Exception
 
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 handler) throws SAXException
 
1136
    {
 
1137
        if (recorder == null) {
 
1138
            throw new SAXException(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 handler) throws SAXException
 
1150
    {
 
1151
        if (recorder == null) {
 
1152
            throw new SAXException(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
 
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 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
 
1217
    {
 
1218
        if (textRep != null) {
 
1219
            boolean oldPretty = outputContext.getPretty();
 
1220
            outputContext.setPretty(false);
 
1221
            if (textRep instanceof CDATASection) {
 
1222
                outputContext.writeString("<![CDATA[");
 
1223
                outputContext.writeString(textRep.getData());
 
1224
                outputContext.writeString("]]>");
 
1225
            } else if (textRep instanceof Comment) {
 
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 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(namespaceURI, name),
 
1248
                              attributes,
 
1249
                              objectValue);
 
1250
            return;
 
1251
        }
 
1252
 
 
1253
        outputContext.startElement(new QName(namespaceURI, name), attributes);
 
1254
        if (children != null) {
 
1255
            for (Iterator 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 toString() {
 
1271
        try {
 
1272
            return getAsString();
 
1273
        }
 
1274
        catch( Exception 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();
 
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 addChildElement(Name childName) throws SOAPException {
 
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 addChildElement(String localName) throws SOAPException {
 
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 addChildElement(String localName,
 
1337
                                       String prefixName) throws SOAPException {
 
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 addChildElement(String localName,
 
1355
                                       String childPrefix,
 
1356
                                       String uri) throws SOAPException {
 
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 addChildElement(SOAPElement element)
 
1371
        throws SOAPException {
 
1372
        try {
 
1373
            addChild((MessageElement)element);
 
1374
            setDirty();
 
1375
            return element;
 
1376
        } catch (ClassCastException e) {
 
1377
            throw new SOAPException(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 addTextNode(String s) throws SOAPException {
 
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 e) {
 
1392
            Text text = new org.apache.axis.message.Text(s);
 
1393
            this.appendChild(text);
 
1394
            return this;
 
1395
        } catch (ClassCastException e) {
 
1396
            throw new SOAPException(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 addAttribute(Name attrName, String value)
 
1409
        throws SOAPException {
 
1410
        try {
 
1411
            addAttribute(attrName.getPrefix(), attrName.getURI(), attrName.getLocalName(), value);
 
1412
        } catch (RuntimeException t) {
 
1413
            throw new SOAPException(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 addNamespaceDeclaration(String prefix,
 
1430
                                               String uri)
 
1431
        throws SOAPException {
 
1432
        try {
 
1433
            Mapping map = new Mapping(uri, prefix);
 
1434
            addMapping(map);
 
1435
        } catch (RuntimeException t) {
 
1436
            //TODO: why is this here? Nowhere else do we turn runtimes into SOAPExceptions.
 
1437
            throw new SOAPException(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 getAttributeValue(Name 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 getAllAttributes() {
 
1461
        int num = attributes.getLength();
 
1462
        Vector attrs = new Vector(num);
 
1463
        for (int i = 0; i < num; i++) {
 
1464
            String q = attributes.getQName(i);
 
1465
            String 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 getNamespacePrefixes() {
 
1491
        Vector prefixes = new Vector();
 
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 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 attrName) {
 
1514
        AttributesImpl 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 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 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 qname) {
 
1566
        if (children != null) {
 
1567
            for (Iterator 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 getChildElements(QName qname) {
 
1585
        initializeChildren();
 
1586
        int num = children.size();
 
1587
        Vector c = new Vector(num);
 
1588
        for (int i = 0; i < num; i++) {
 
1589
            MessageElement child = (MessageElement)children.get(i);
 
1590
            Name 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 getChildElements(Name childName) {
 
1609
        return getChildElements(new QName(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 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 attrName) throws DOMException {
 
1629
        AttributesImpl impl =  (AttributesImpl)attributes;
 
1630
        int index = impl.getIndex(attrName);
 
1631
        if(index >= 0){
 
1632
            AttributesImpl newAttrs = new AttributesImpl();
 
1633
            // copy except the removed attribute
 
1634
            for(int i = 0; i < impl.getLength(); i++){ // shift after removal
 
1635
                if(i != index){
 
1636
                    String uri = impl.getURI(i);
 
1637
                    String local = impl.getLocalName(i);
 
1638
                    String qname = impl.getQName(i);
 
1639
                    String type = impl.getType(i);
 
1640
                    String 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 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 getAttribute(String 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 namespace, String localName) throws DOMException {
 
1689
        makeAttributesEditable();
 
1690
        Name 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 name, String value) throws DOMException {
 
1702
        AttributesImpl impl =  makeAttributesEditable();
 
1703
        int index = impl.getIndex(name);
 
1704
        if (index < 0) { // not found
 
1705
            String uri = "";
 
1706
            String localname = name;
 
1707
            String qname = name;
 
1708
            String 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 namespace, String 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 getAttributeNode(String 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 removeAttributeNode(Attr oldAttr) throws DOMException {
 
1759
        makeAttributesEditable();
 
1760
        Name 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 setAttributeNode(Attr newAttr) throws DOMException {
 
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 setAttributeNodeNS(Attr newAttr) throws DOMException {
 
1787
        //attributes.
 
1788
        AttributesImpl 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 getElementsByTagName(String tagName) {
 
1804
        NodeListImpl nodelist = new NodeListImpl();
 
1805
        for (int i = 0; children != null && i < children.size(); i++) {
 
1806
            if (children.get(i) instanceof Node) {
 
1807
                Node el = (Node)children.get(i);
 
1808
                if (el.getLocalName() != null && el.getLocalName()
 
1809
                                .equals(tagName))
 
1810
                    nodelist.addNode(el);
 
1811
                if (el instanceof Element) {
 
1812
                    NodeList grandchildren =
 
1813
                            ((Element)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 getAttributeNS(String namespaceURI, String 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 namespaceURI, String qualifiedName,
 
1853
                               String value)
 
1854
        throws DOMException
 
1855
    {
 
1856
        AttributesImpl attributes = makeAttributesEditable();
 
1857
        String 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 getAttributeNodeNS(String namespace, String 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 getElementsByTagNameNS(String namespace,
 
1887
                                           String 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 getElementsNS(org.w3c.dom.Element parentElement,
 
1900
                                     String namespace, String localName)
 
1901
    {
 
1902
        NodeList 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 child = (Element) 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 item(int index) {
 
1928
        if (children != null && children.size() > index) {
 
1929
            return (Node) 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 vec, String namespace,
 
1952
                               String localPart)
 
1953
    {
 
1954
        if (vec.isEmpty()) {
 
1955
            return null;
 
1956
        }
 
1957
 
 
1958
        QName qname = new QName(namespace, localPart);
 
1959
        Enumeration 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 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 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 source)
 
2007
    {
 
2008
        dest.setPrefix(source.getPrefix());
 
2009
        if(source.getLocalName() != null) {
 
2010
            dest.setQName(new QName(source.getNamespaceURI(), source.getLocalName()));
 
2011
        }
 
2012
        else
 
2013
        {
 
2014
            dest.setQName(new QName(source.getNamespaceURI(), source.getNodeName()));
 
2015
        }
 
2016
 
 
2017
        NamedNodeMap attrs = source.getAttributes();
 
2018
        for(int i = 0; i < attrs.getLength(); i++){
 
2019
            Node 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 children = source.getChildNodes();
 
2041
        for(int i = 0; i < children.getLength(); i++){
 
2042
            Node 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)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 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 i = getChildElements(); i.hasNext(); ) {
 
2094
            org.apache.axis.message.NodeImpl n = (org.apache.axis.message.NodeImpl) i.next();
 
2095
            if (n instanceof org.apache.axis.message.Text) {
 
2096
                org.apache.axis.message.Text textNode = (org.apache.axis.message.Text) n;
 
2097
                return textNode.getNodeValue();
 
2098
            }
 
2099
        }
 
2100
 
 
2101
        return null;
 
2102
    }
 
2103
 
 
2104
    protected String getValueDOM() {
 
2105
        try {
 
2106
            Element element = getAsDOM();
 
2107
            if (element.hasChildNodes()) {
 
2108
                Node node = element.getFirstChild();
 
2109
                if (node.getNodeType() == Node.TEXT_NODE) {
 
2110
                    return node.getNodeValue();
 
2111
                }
 
2112
            }
 
2113
        } catch (Exception t) {
 
2114
            log.debug("getValue()", t);
 
2115
        }
 
2116
        return null;
 
2117
    }
 
2118
 
 
2119
    public void setValue( String value )
 
2120
    {
 
2121
        // if possible, get objectValue in sync with Node value
 
2122
        if (children==null) {
 
2123
            try {
 
2124
                setObjectValue(value);
 
2125
            } catch ( SOAPException soape ) {
 
2126
                log.debug("setValue()", soape);
 
2127
            }
 
2128
        }
 
2129
        super.setValue(value);
 
2130
    }
 
2131
 
 
2132
    public Document getOwnerDocument() {
 
2133
        Document doc = null;
 
2134
        if (context != null && context.getEnvelope() != null &&
 
2135
                context.getEnvelope().getOwnerDocument() != null) {
 
2136
            doc = context.getEnvelope().getOwnerDocument();
 
2137
        }
 
2138
        if(doc == null) {
 
2139
            doc = super.getOwnerDocument();
 
2140
        }
 
2141
        if (doc == null) {
 
2142
            doc = new SOAPDocumentImpl(null);
 
2143
        }
 
2144
        return doc;
 
2145
    }
 
2146
}