1/*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.xml.internal.messaging.saaj.soap.impl;
27
28import java.net.URI;
29import java.net.URISyntaxException;
30import java.util.logging.Level;
31import java.util.logging.Logger;
32
33import javax.xml.namespace.QName;
34
35import org.w3c.dom.Node;
36
37import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
38import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument;
39import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
40import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
41import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants;
42import com.sun.xml.internal.messaging.saaj.util.NamespaceContextIterator;
43import java.util.ArrayList;
44import java.util.Iterator;
45import java.util.NoSuchElementException;
46import javax.xml.soap.Name;
47import javax.xml.soap.SOAPBodyElement;
48import javax.xml.soap.SOAPConstants;
49import javax.xml.soap.SOAPElement;
50import javax.xml.soap.SOAPException;
51import org.w3c.dom.Attr;
52import org.w3c.dom.CharacterData;
53import org.w3c.dom.DOMException;
54import org.w3c.dom.Document;
55import org.w3c.dom.DocumentFragment;
56import org.w3c.dom.Element;
57import org.w3c.dom.NamedNodeMap;
58import org.w3c.dom.NodeList;
59import org.w3c.dom.TypeInfo;
60import org.w3c.dom.UserDataHandler;
61
62public class ElementImpl implements SOAPElement, SOAPBodyElement {
63
64    public static final String DSIG_NS = "http://www.w3.org/2000/09/xmldsig#".intern();
65    public static final String XENC_NS = "http://www.w3.org/2001/04/xmlenc#".intern();
66    public static final String WSU_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd".intern();
67
68    private transient AttributeManager encodingStyleAttribute = new AttributeManager();
69
70    protected QName elementQName;
71
72    private Element element;
73
74    private SOAPDocumentImpl soapDocument;
75
76    @Override
77    public String getTagName() {
78        return element.getTagName();
79    }
80
81    @Override
82    public String getAttribute(String name) {
83        return element.getAttribute(name);
84    }
85
86    @Override
87    public void setAttribute(String name, String value) throws DOMException {
88        boolean isQualifiedName = (name.indexOf(":") > 0);
89        //this is because of BugfixTest#testCR7020991, after removal internal dependencies
90        //SOAPDocumentImpl#createAttribute is not called anymore from xerces parent
91        if (isQualifiedName) {
92            String nsUri = null;
93            String prefix = name.substring(0, name.indexOf(":"));
94            //cannot do anything to resolve the URI if prefix is not
95            //XMLNS.
96            if (XMLNS.equals(prefix)) {
97                nsUri = ElementImpl.XMLNS_URI;
98                setAttributeNS(nsUri, name, value);
99                return;
100            }
101        }
102        element.setAttribute(name, value);
103    }
104
105    @Override
106    public void removeAttribute(String name) throws DOMException {
107        element.removeAttribute(name);
108    }
109
110    @Override
111    public Attr getAttributeNode(String name) {
112        return element.getAttributeNode(name);
113    }
114
115    @Override
116    public Attr setAttributeNode(Attr newAttr) throws DOMException {
117        return element.setAttributeNode(newAttr);
118    }
119
120    @Override
121    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
122        return element.removeAttributeNode(oldAttr);
123    }
124
125    @Override
126    public NodeList getElementsByTagName(String name) {
127        return new NodeListImpl(soapDocument, element.getElementsByTagName(name));
128    }
129
130    @Override
131    public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
132        return element.getAttributeNS(namespaceURI, localName);
133    }
134
135    protected static final Logger log =
136        Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN,
137                         "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings");
138
139    /**
140     * XML Information Set REC
141     * all namespace attributes (including those named xmlns,
142     * whose [prefix] property has no value) have a namespace URI of http://www.w3.org/2000/xmlns/
143     */
144    public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/".intern();
145
146    /**
147     * The XML Namespace ("http://www.w3.org/XML/1998/namespace"). This is
148     * the Namespace URI that is automatically mapped to the "xml" prefix.
149     */
150    public final static String XML_URI = "http://www.w3.org/XML/1998/namespace".intern();
151
152    private final static String XMLNS = "xmlns".intern();
153
154    public ElementImpl(SOAPDocumentImpl ownerDoc, Name name) {
155        this.soapDocument = ownerDoc;
156        this.element = ownerDoc.getDomDocument().createElementNS(name.getURI(), name.getQualifiedName());
157        elementQName = NameImpl.convertToQName(name);
158        soapDocument.register(this);
159    }
160
161    public ElementImpl(SOAPDocumentImpl ownerDoc, QName name) {
162        this.soapDocument = ownerDoc;
163        this.element = ownerDoc.getDomDocument().createElementNS(name.getNamespaceURI(), getQualifiedName(name));
164        elementQName = name;
165        soapDocument.register(this);
166    }
167
168    public ElementImpl(SOAPDocumentImpl ownerDoc, Element domElement) {
169        this.element = domElement;
170        this.soapDocument = ownerDoc;
171        this.elementQName = new QName(domElement.getNamespaceURI(), domElement.getLocalName());
172        soapDocument.register(this);
173    }
174
175    public ElementImpl(
176        SOAPDocumentImpl ownerDoc,
177        String uri,
178        String qualifiedName) {
179
180        this.soapDocument = ownerDoc;
181        this.element = ownerDoc.getDomDocument().createElementNS(uri, qualifiedName);
182        elementQName =
183            new QName(uri, getLocalPart(qualifiedName), getPrefix(qualifiedName));
184        soapDocument.register(this);
185    }
186
187    public void ensureNamespaceIsDeclared(String prefix, String uri) {
188        String alreadyDeclaredUri = getNamespaceURI(prefix);
189        if (alreadyDeclaredUri == null || !alreadyDeclaredUri.equals(uri)) {
190            try {
191                addNamespaceDeclaration(prefix, uri);
192            } catch (SOAPException e) { /*ignore*/
193            }
194        }
195    }
196
197    @Override
198    public Document getOwnerDocument() {
199        return soapDocument;
200    }
201
202    @Override
203    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
204        return soapDocument.findIfPresent(element.insertBefore(soapDocument.getDomNode(newChild), soapDocument.getDomNode(refChild)));
205    }
206
207    @Override
208    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
209        return soapDocument.findIfPresent(element.replaceChild(soapDocument.getDomNode(newChild), soapDocument.getDomNode(oldChild)));
210    }
211
212    @Override
213    public Node removeChild(Node oldChild) throws DOMException {
214        return soapDocument.findIfPresent(element.removeChild(soapDocument.getDomNode(oldChild)));
215    }
216
217    @Override
218    public Node appendChild(Node newChild) throws DOMException {
219        return soapDocument.findIfPresent(element.appendChild(soapDocument.getDomNode(newChild)));
220    }
221
222    @Override
223    public boolean hasChildNodes() {
224        return element.hasChildNodes();
225    }
226
227    @Override
228    public Node cloneNode(boolean deep) {
229        Node elementNSNode = element.cloneNode(deep);
230        soapDocument.registerChildNodes(elementNSNode, deep);
231        return soapDocument.findIfPresent(soapDocument.getDomNode(elementNSNode));
232    }
233
234    @Override
235    public void normalize() {
236        element.normalize();
237    }
238
239    @Override
240    public boolean isSupported(String feature, String version) {
241        return element.isSupported(feature, version);
242    }
243
244    @Override
245    public String getNamespaceURI() {
246        return element.getNamespaceURI();
247    }
248
249    @Override
250    public String getPrefix() {
251        return element.getPrefix();
252    }
253
254    @Override
255    public void setPrefix(String prefix) throws DOMException {
256        element.setPrefix(prefix);
257    }
258
259    @Override
260    public String getLocalName() {
261        return element.getLocalName();
262    }
263
264    @Override
265    public boolean hasAttributes() {
266        return element.hasAttributes();
267    }
268
269    @Override
270    public String getBaseURI() {
271        return element.getBaseURI();
272    }
273
274    @Override
275    public short compareDocumentPosition(Node other) throws DOMException {
276        return element.compareDocumentPosition(soapDocument.getDomNode(other));
277    }
278
279    @Override
280    public String getTextContent() throws DOMException {
281        return element.getTextContent();
282    }
283
284    @Override
285    public void setTextContent(String textContent) throws DOMException {
286        element.setTextContent(textContent);
287    }
288
289    @Override
290    public boolean isSameNode(Node other) {
291        return element.isSameNode(soapDocument.getDomNode(other));
292    }
293
294    @Override
295    public String lookupPrefix(String namespaceURI) {
296        return element.lookupPrefix(namespaceURI);
297    }
298
299    @Override
300    public boolean isDefaultNamespace(String namespaceURI) {
301        return element.isDefaultNamespace(namespaceURI);
302    }
303
304    @Override
305    public String lookupNamespaceURI(String prefix) {
306        return element.lookupNamespaceURI(prefix);
307    }
308
309    @Override
310    public boolean isEqualNode(Node arg) {
311        return element.isEqualNode(soapDocument.getDomNode(arg));
312    }
313
314    @Override
315    public Object getFeature(String feature, String version) {
316        return element.getFeature(feature, version);
317    }
318
319    @Override
320    public Object setUserData(String key, Object data, UserDataHandler handler) {
321        return element.setUserData(key, data, handler);
322    }
323
324    @Override
325    public Object getUserData(String key) {
326        return element.getUserData(key);
327    }
328
329    @Override
330    public SOAPElement addChildElement(Name name) throws SOAPException {
331        return  addElement(name);
332    }
333
334    @Override
335    public SOAPElement addChildElement(QName qname) throws SOAPException {
336        return  addElement(qname);
337    }
338
339    @Override
340    public SOAPElement addChildElement(String localName) throws SOAPException {
341        String nsUri = getNamespaceURI("");
342        Name name = (nsUri == null || nsUri.isEmpty())
343                ?  NameImpl.createFromUnqualifiedName(localName)
344                :  NameImpl.createFromQualifiedName(localName, nsUri);
345        return addChildElement(name);
346    }
347
348    @Override
349    public SOAPElement addChildElement(String localName, String prefix)
350        throws SOAPException {
351        String uri = getNamespaceURI(prefix);
352        if (uri == null) {
353            log.log(
354                Level.SEVERE,
355                "SAAJ0101.impl.parent.of.body.elem.mustbe.body",
356                new String[] { prefix });
357            throw new SOAPExceptionImpl(
358                "Unable to locate namespace for prefix " + prefix);
359        }
360        return addChildElement(localName, prefix, uri);
361    }
362
363    @Override
364    public String getNamespaceURI(String prefix) {
365
366        if ("xmlns".equals(prefix)) {
367            return XMLNS_URI;
368        }
369
370        if("xml".equals(prefix)) {
371            return XML_URI;
372        }
373
374        if ("".equals(prefix)) {
375
376            org.w3c.dom.Node currentAncestor = this;
377            while (currentAncestor != null &&
378                   !(currentAncestor instanceof Document)) {
379
380                if (currentAncestor instanceof ElementImpl) {
381                    /*
382                    QName name = ((ElementImpl) currentAncestor).getElementQName();
383                    if (prefix.equals(name.getPrefix())) {
384                        String uri = name.getNamespaceURI();
385                        if ("".equals(uri)) {
386                            return null;
387                        }
388                        else {
389                            return uri;
390                        }
391                    }*/
392                    if (((Element) currentAncestor).hasAttributeNS(
393                            XMLNS_URI, "xmlns")) {
394
395                        String uri =
396                            ((Element) currentAncestor).getAttributeNS(
397                                XMLNS_URI, "xmlns");
398                        if ("".equals(uri))
399                            return null;
400                        else {
401                            return uri;
402                        }
403                    }
404                }
405                currentAncestor = currentAncestor.getParentNode();
406            }
407
408        } else if (prefix != null) {
409            // Find if there's an ancester whose name contains this prefix
410            org.w3c.dom.Node currentAncestor = this;
411
412//            String uri = currentAncestor.lookupNamespaceURI(prefix);
413//            return uri;
414            while (currentAncestor != null &&
415                   !(currentAncestor instanceof Document)) {
416
417               /* if (prefix.equals(currentAncestor.getPrefix())) {
418                    String uri = currentAncestor.getNamespaceURI();
419                    // this is because the javadoc says getNamespaceURI() is not a computed value
420                    // and URI for a non-empty prefix cannot be null
421                    if (uri != null)
422                        return uri;
423                }*/
424                //String uri = currentAncestor.lookupNamespaceURI(prefix);
425                //if (uri != null) {
426                //    return uri;
427                //}
428
429                if (((Element) currentAncestor).hasAttributeNS(
430                        XMLNS_URI, prefix)) {
431                    return ((Element) currentAncestor).getAttributeNS(
432                               XMLNS_URI, prefix);
433                }
434
435                currentAncestor = currentAncestor.getParentNode();
436            }
437        }
438
439        return null;
440    }
441
442    @Override
443    public SOAPElement setElementQName(QName newName) throws SOAPException {
444        ElementImpl copy =
445            new ElementImpl((SOAPDocumentImpl) getOwnerDocument(), newName);
446        return replaceElementWithSOAPElement(this,copy);
447    }
448
449    @Override
450    public QName createQName(String localName, String prefix)
451        throws SOAPException {
452        String uri = getNamespaceURI(prefix);
453        if (uri == null) {
454            log.log(Level.SEVERE, "SAAJ0102.impl.cannot.locate.ns",
455                    new Object[] {prefix});
456            throw new SOAPException("Unable to locate namespace for prefix "
457                                    + prefix);
458        }
459        return new QName(uri, localName, prefix);
460    }
461
462    public String getNamespacePrefix(String uri) {
463
464        NamespaceContextIterator eachNamespace = getNamespaceContextNodes();
465        while (eachNamespace.hasNext()) {
466            org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
467            if (namespaceDecl.getNodeValue().equals(uri)) {
468                String candidatePrefix = namespaceDecl.getLocalName();
469                if ("xmlns".equals(candidatePrefix))
470                    return "";
471                else
472                    return candidatePrefix;
473            }
474        }
475
476        // Find if any of the ancestors' name has this uri
477        org.w3c.dom.Node currentAncestor = this;
478        while (currentAncestor != null &&
479               !(currentAncestor instanceof Document)) {
480
481            if (uri.equals(currentAncestor.getNamespaceURI()))
482                return currentAncestor.getPrefix();
483            currentAncestor = currentAncestor.getParentNode();
484        }
485
486        return null;
487    }
488
489    protected org.w3c.dom.Attr getNamespaceAttr(String prefix) {
490        NamespaceContextIterator eachNamespace = getNamespaceContextNodes();
491        if (!"".equals(prefix))
492            prefix = ":"+prefix;
493        while (eachNamespace.hasNext()) {
494            org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
495            if (!"".equals(prefix)) {
496                if (namespaceDecl.getNodeName().endsWith(prefix))
497                    return namespaceDecl;
498            } else {
499                if (namespaceDecl.getNodeName().equals("xmlns"))
500                    return namespaceDecl;
501            }
502        }
503        return null;
504    }
505
506    public NamespaceContextIterator getNamespaceContextNodes() {
507        return getNamespaceContextNodes(true);
508    }
509
510    public NamespaceContextIterator getNamespaceContextNodes(boolean traverseStack) {
511        return new NamespaceContextIterator(this, traverseStack);
512    }
513
514    @Override
515    public SOAPElement addChildElement(
516        String localName,
517        String prefix,
518        String uri)
519        throws SOAPException {
520
521        SOAPElement newElement = createElement(NameImpl.create(localName, prefix, uri));
522        addNode(newElement);
523        return convertToSoapElement(newElement);
524    }
525
526    @Override
527    public SOAPElement addChildElement(SOAPElement element)
528        throws SOAPException {
529
530        // check if Element falls in SOAP 1.1 or 1.2 namespace.
531        String elementURI = element.getElementName().getURI();
532        String localName = element.getLocalName();
533
534        if ((SOAPConstants.URI_NS_SOAP_ENVELOPE).equals(elementURI)
535            || (SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE).equals(elementURI)) {
536
537
538            if ("Envelope".equalsIgnoreCase(localName) ||
539                "Header".equalsIgnoreCase(localName) || "Body".equalsIgnoreCase(localName)) {
540                log.severe("SAAJ0103.impl.cannot.add.fragements");
541                throw new SOAPExceptionImpl(
542                    "Cannot add fragments which contain elements "
543                        + "which are in the SOAP namespace");
544            }
545
546            if ("Fault".equalsIgnoreCase(localName) && !"Body".equalsIgnoreCase(this.getLocalName())) {
547                log.severe("SAAJ0154.impl.adding.fault.to.nonbody");
548                throw new SOAPExceptionImpl("Cannot add a SOAPFault as a child of " + this.getLocalName());
549            }
550
551            if ("Detail".equalsIgnoreCase(localName) && !"Fault".equalsIgnoreCase(this.getLocalName())) {
552                log.severe("SAAJ0155.impl.adding.detail.nonfault");
553                throw new SOAPExceptionImpl("Cannot add a Detail as a child of " + this.getLocalName());
554            }
555
556            if ("Fault".equalsIgnoreCase(localName)) {
557               // if body is not empty throw an exception
558               if (!elementURI.equals(this.getElementName().getURI())) {
559                   log.severe("SAAJ0158.impl.version.mismatch.fault");
560                   throw new SOAPExceptionImpl("SOAP Version mismatch encountered when trying to add SOAPFault to SOAPBody");
561               }
562               Iterator<javax.xml.soap.Node> it = this.getChildElements();
563               if (it.hasNext()) {
564                   log.severe("SAAJ0156.impl.adding.fault.error");
565                   throw new SOAPExceptionImpl("Cannot add SOAPFault as a child of a non-Empty SOAPBody");
566               }
567            }
568        }
569
570        // preserve the encodingStyle attr as it may get lost in the import
571        String encodingStyle = element.getEncodingStyle();
572
573        final Element importedElement = importElement(element);
574        addNode(importedElement);
575
576        final SOAPElement converted = convertToSoapElement(importedElement);
577
578        if (encodingStyle != null)
579            converted.setEncodingStyle(encodingStyle);
580
581        return converted;
582    }
583
584    protected Element importElement(Element element) {
585        Document document = getOwnerDocument();
586        Document oldDocument = element.getOwnerDocument();
587        if (!oldDocument.equals(document)) {
588            return (Element) document.importNode(element, true);
589        } else {
590            return element;
591        }
592    }
593
594    protected SOAPElement addElement(Name name) throws SOAPException {
595        SOAPElement newElement = createElement(name);
596        addNode(((ElementImpl) newElement).getDomElement());
597        return newElement;
598    }
599
600    protected SOAPElement addElement(QName name) throws SOAPException {
601        SOAPElement newElement = createElement(name);
602        addNode(newElement);
603        return newElement;
604    }
605
606    protected SOAPElement createElement(Name name) {
607
608        if (isNamespaceQualified(name)) {
609            return (SOAPElement)
610                getOwnerDocument().createElementNS(
611                                       name.getURI(),
612                                       name.getQualifiedName());
613        } else {
614            return (SOAPElement)
615                getOwnerDocument().createElement(name.getQualifiedName());
616        }
617    }
618
619    protected SOAPElement createElement(QName name) {
620
621        if (isNamespaceQualified(name)) {
622            return (SOAPElement)
623                getOwnerDocument().createElementNS(
624                                       name.getNamespaceURI(),
625                                       getQualifiedName(name));
626        } else {
627            return (SOAPElement)
628                getOwnerDocument().createElement(getQualifiedName(name));
629        }
630    }
631
632    protected void addNode(org.w3c.dom.Node newElement) throws SOAPException {
633        insertBefore(soapDocument.getDomNode(newElement), null);
634
635        if (getOwnerDocument() instanceof DocumentFragment)
636            return;
637
638        if (newElement instanceof ElementImpl) {
639            ElementImpl element = (ElementImpl) newElement;
640            QName elementName = element.getElementQName();
641            if (!"".equals(elementName.getNamespaceURI())) {
642                element.ensureNamespaceIsDeclared(
643                    elementName.getPrefix(), elementName.getNamespaceURI());
644            }
645        }
646
647    }
648
649    Element getFirstChildElement() {
650        Node child = getFirstChild();
651        while (child != null) {
652            if (child instanceof Element) {
653                return (Element) soapDocument.find(child);
654            }
655            child = child.getNextSibling();
656        }
657        return null;
658    }
659
660    protected SOAPElement findChild(NameImpl name) {
661        Node eachChild = getFirstChild();
662        while (eachChild != null) {
663            if (eachChild instanceof Element) {
664                SOAPElement eachChildSoap = (SOAPElement) soapDocument.find(eachChild);
665                if (eachChildSoap != null) {
666                    if (eachChildSoap.getElementName().equals(name)) {
667                        return eachChildSoap;
668                    }
669                }
670            }
671            eachChild = eachChild.getNextSibling();
672        }
673        return null;
674    }
675
676    protected SOAPElement findAndConvertChildElement(NameImpl name) {
677        Iterator<Node> eachChild = getChildElementNodes();
678        while (eachChild.hasNext()) {
679            SOAPElement child = (SOAPElement) eachChild.next();
680            if (child.getElementName().equals(name)) {
681                return child;
682            }
683        }
684
685        return null;
686    }
687
688    @Override
689    public SOAPElement addTextNode(String text) throws SOAPException {
690        if (text.startsWith(CDATAImpl.cdataUC)
691            || text.startsWith(CDATAImpl.cdataLC))
692            return addCDATA(
693                text.substring(CDATAImpl.cdataUC.length(), text.length() - 3));
694        return addText(text);
695    }
696
697    protected SOAPElement addCDATA(String text) throws SOAPException {
698        org.w3c.dom.Text cdata =
699                getOwnerDocument().createCDATASection(text);
700        addNode(cdata);
701        return this;
702    }
703
704    protected SOAPElement addText(String text) throws SOAPException {
705        org.w3c.dom.Text textNode =
706                getOwnerDocument().createTextNode(text);
707        addNode(textNode);
708        return this;
709    }
710
711    @Override
712    public SOAPElement addAttribute(Name name, String value)
713        throws SOAPException {
714        addAttributeBare(name, value);
715        if (!"".equals(name.getURI())) {
716            ensureNamespaceIsDeclared(name.getPrefix(), name.getURI());
717        }
718        return this;
719    }
720
721    @Override
722    public SOAPElement addAttribute(QName qname, String value)
723        throws SOAPException {
724        addAttributeBare(qname, value);
725        if (!"".equals(qname.getNamespaceURI())) {
726            ensureNamespaceIsDeclared(qname.getPrefix(), qname.getNamespaceURI());
727        }
728        return this;
729    }
730
731    private void addAttributeBare(Name name, String value) {
732        addAttributeBare(
733            name.getURI(),
734            name.getPrefix(),
735            name.getQualifiedName(),
736            value);
737    }
738    private void addAttributeBare(QName name, String value) {
739        addAttributeBare(
740            name.getNamespaceURI(),
741            name.getPrefix(),
742            getQualifiedName(name),
743            value);
744    }
745
746    private void addAttributeBare(
747        String uri,
748        String prefix,
749        String qualifiedName,
750        String value) {
751
752        uri = uri.length() == 0 ? null : uri;
753        if (qualifiedName.equals("xmlns")) {
754            uri = XMLNS_URI;
755        }
756
757        if (uri == null) {
758            setAttribute(qualifiedName, value);
759        } else {
760            setAttributeNS(uri, qualifiedName, value);
761        }
762    }
763
764    @Override
765    public SOAPElement addNamespaceDeclaration(String prefix, String uri)
766        throws SOAPException {
767        if (prefix.length() > 0) {
768            setAttributeNS(XMLNS_URI, "xmlns:" + prefix, uri);
769        } else {
770            setAttributeNS(XMLNS_URI, "xmlns", uri);
771        }
772        //Fix for CR:6474641
773        //tryToFindEncodingStyleAttributeName();
774        return this;
775    }
776
777    @Override
778    public String getAttributeValue(Name name) {
779        return getAttributeValueFrom(this, name);
780    }
781
782    @Override
783    public String getAttributeValue(QName qname) {
784        return getAttributeValueFrom(
785                   this,
786                   qname.getNamespaceURI(),
787                   qname.getLocalPart(),
788                   qname.getPrefix(),
789                   getQualifiedName(qname));
790    }
791
792    @Override
793    public Iterator<Name> getAllAttributes() {
794        Iterator<Name> i = getAllAttributesFrom(this);
795        ArrayList<Name> list = new ArrayList<>();
796        while (i.hasNext()) {
797            Name name = i.next();
798            if (!"xmlns".equalsIgnoreCase(name.getPrefix()))
799                list.add(name);
800        }
801        return list.iterator();
802    }
803
804    @Override
805    public Iterator<QName> getAllAttributesAsQNames() {
806        Iterator<Name> i = getAllAttributesFrom(this);
807        ArrayList<QName> list = new ArrayList<>();
808        while (i.hasNext()) {
809            Name name = i.next();
810            if (!"xmlns".equalsIgnoreCase(name.getPrefix())) {
811                list.add(NameImpl.convertToQName(name));
812            }
813        }
814        return list.iterator();
815    }
816
817
818    @Override
819    public Iterator<String> getNamespacePrefixes() {
820        return doGetNamespacePrefixes(false);
821    }
822
823    @Override
824    public Iterator<String> getVisibleNamespacePrefixes() {
825        return doGetNamespacePrefixes(true);
826    }
827
828    protected Iterator<String> doGetNamespacePrefixes(final boolean deep) {
829        return new Iterator<String>() {
830            String next = null;
831            String last = null;
832            NamespaceContextIterator eachNamespace =
833                getNamespaceContextNodes(deep);
834
835            void findNext() {
836                while (next == null && eachNamespace.hasNext()) {
837                    String attributeKey =
838                        eachNamespace.nextNamespaceAttr().getNodeName();
839                    if (attributeKey.startsWith("xmlns:")) {
840                        next = attributeKey.substring("xmlns:".length());
841                    }
842                }
843            }
844
845            @Override
846            public boolean hasNext() {
847                findNext();
848                return next != null;
849            }
850
851            @Override
852            public String next() {
853                findNext();
854                if (next == null) {
855                    throw new NoSuchElementException();
856                }
857
858                last = next;
859                next = null;
860                return last;
861            }
862
863            @Override
864            public void remove() {
865                if (last == null) {
866                    throw new IllegalStateException();
867                }
868                eachNamespace.remove();
869                next = null;
870                last = null;
871            }
872        };
873    }
874
875    @Override
876    public Name getElementName() {
877        return NameImpl.convertToName(elementQName);
878    }
879
880    @Override
881    public QName getElementQName() {
882        return elementQName;
883    }
884
885    @Override
886    public boolean removeAttribute(Name name) {
887        return removeAttribute(name.getURI(), name.getLocalName());
888    }
889
890    @Override
891    public boolean removeAttribute(QName name) {
892        return removeAttribute(name.getNamespaceURI(), name.getLocalPart());
893    }
894
895    private boolean removeAttribute(String uri, String localName) {
896        String nonzeroLengthUri =
897            (uri == null || uri.length() == 0) ? null : uri;
898        org.w3c.dom.Attr attribute =
899            getAttributeNodeNS(nonzeroLengthUri, localName);
900        if (attribute == null) {
901            return false;
902        }
903        removeAttributeNode(attribute);
904        return true;
905    }
906
907    @Override
908    public boolean removeNamespaceDeclaration(String prefix) {
909        org.w3c.dom.Attr declaration = getNamespaceAttr(prefix);
910        if (declaration == null) {
911            return false;
912        }
913        try {
914            removeAttributeNode(declaration);
915        } catch (DOMException de) {
916            // ignore
917        }
918        return true;
919    }
920
921    @Override
922    public Iterator<javax.xml.soap.Node> getChildElements() {
923        return getChildElementsFrom(this);
924    }
925
926    protected SOAPElement convertToSoapElement(Element element) {
927        final Node soapNode = soapDocument.findIfPresent(element);
928        if (soapNode instanceof SOAPElement) {
929            return (SOAPElement) soapNode;
930        } else {
931            return replaceElementWithSOAPElement(
932                element,
933                (ElementImpl) createElement(NameImpl.copyElementName(element)));
934        }
935    }
936
937    protected TextImpl convertToSoapText(CharacterData characterData) {
938        final Node soapNode = getSoapDocument().findIfPresent(characterData);
939        if (soapNode instanceof TextImpl) {
940            return (TextImpl) soapNode;
941        } else {
942            TextImpl t = null;
943            switch (characterData.getNodeType()) {
944                case CDATA_SECTION_NODE:
945                    t = new CDATAImpl(getSoapDocument(), characterData.getData());
946                    break;
947                case COMMENT_NODE:
948                    t = new SOAPCommentImpl(getSoapDocument(), characterData.getData());
949                    break;
950                case TEXT_NODE:
951                    t = new SOAPTextImpl(getSoapDocument(), characterData.getData());
952                    break;
953            }
954            Node parent = getSoapDocument().find(characterData.getParentNode());
955            if (parent != null) {
956                parent.replaceChild(t, characterData);
957            } // XXX else throw an exception?
958
959            return t;
960
961//            return replaceElementWithSOAPElement(
962//                element,
963//                (ElementImpl) createElement(NameImpl.copyElementName(element)));
964        }
965    }
966
967    protected SOAPElement replaceElementWithSOAPElement(
968        Element element,
969        ElementImpl copy) {
970
971        Iterator<Name> eachAttribute = getAllAttributesFrom(element);
972        while (eachAttribute.hasNext()) {
973            Name name = eachAttribute.next();
974            copy.addAttributeBare(name, getAttributeValueFrom(element, name));
975        }
976
977        Iterator<Node> eachChild = getChildElementsFromDOM(element);
978        while (eachChild.hasNext()) {
979            Node nextChild = eachChild.next();
980            copy.insertBefore(nextChild, null);
981        }
982
983        Node parent = soapDocument.find(element.getParentNode());
984        if (parent != null) {
985            parent.replaceChild(copy, element);
986        } // XXX else throw an exception?
987
988        return copy;
989    }
990
991    private Iterator<Node> getChildElementsFromDOM(final Element el) {
992        return new Iterator<Node>() {
993            Node next = el.getFirstChild();
994            Node nextNext = null;
995            Node last = null;
996            Node soapElement = getSoapDocument().findIfPresent(el);
997
998            @Override
999            public boolean hasNext() {
1000                if (next != null) {
1001                    return true;
1002                }
1003                if (nextNext != null) {
1004                    next = nextNext;
1005                }
1006
1007                return next != null;
1008            }
1009
1010            public Node next() {
1011                if (hasNext()) {
1012                    last = next;
1013                    next = null;
1014
1015                    if ((soapElement instanceof ElementImpl)
1016                            && (last instanceof Element)) {
1017                        last =
1018                                ((ElementImpl) soapElement).convertToSoapElement(
1019                                        (Element) last);
1020                    } else if ((soapElement instanceof ElementImpl) && (last instanceof CharacterData)) {
1021                        last = ((ElementImpl) soapElement).convertToSoapText(
1022                                        (CharacterData) last);
1023                    }
1024
1025                    nextNext = last.getNextSibling();
1026                    return last;
1027                }
1028                throw new NoSuchElementException();
1029            }
1030
1031            @Override
1032            public void remove() {
1033                if (last == null) {
1034                    throw new IllegalStateException();
1035                }
1036                Node target = last;
1037                last = null;
1038                el.removeChild(target);
1039            }
1040        };
1041    }
1042
1043    protected Iterator<Node> getChildElementNodes() {
1044        return new Iterator<Node>() {
1045            Iterator<javax.xml.soap.Node> eachNode = getChildElements();
1046            Node next = null;
1047            Node last = null;
1048
1049            @Override
1050            public boolean hasNext() {
1051                if (next == null) {
1052                    while (eachNode.hasNext()) {
1053                        Node node = eachNode.next();
1054                        if (node instanceof Element) {
1055                            next = soapDocument.findIfPresent(node);
1056                            break;
1057                        }
1058                    }
1059                }
1060                return next != null;
1061            }
1062
1063            @Override
1064            public javax.xml.soap.Node next() {
1065                if (hasNext()) {
1066                    last = next;
1067                    next = null;
1068                    return (javax.xml.soap.Node) last;
1069                }
1070                throw new NoSuchElementException();
1071            }
1072
1073            @Override
1074            public void remove() {
1075                if (last == null) {
1076                    throw new IllegalStateException();
1077                }
1078                Node target = last;
1079                last = null;
1080                removeChild(target);
1081            }
1082        };
1083    }
1084
1085    @Override
1086    public Iterator<javax.xml.soap.Node> getChildElements(final Name name) {
1087       return getChildElements(name.getURI(), name.getLocalName());
1088    }
1089
1090    @Override
1091    public Iterator<javax.xml.soap.Node> getChildElements(final QName qname) {
1092        return getChildElements(qname.getNamespaceURI(), qname.getLocalPart());
1093    }
1094
1095    private Iterator<javax.xml.soap.Node> getChildElements(final String nameUri, final String nameLocal) {
1096        return new Iterator<javax.xml.soap.Node>() {
1097            Iterator<Node> eachElement = getChildElementNodes();
1098            Node next = null;
1099            Node last = null;
1100
1101            @Override
1102            public boolean hasNext() {
1103                if (next == null) {
1104                    while (eachElement.hasNext()) {
1105                        Node element = eachElement.next();
1106                        String elementUri = element.getNamespaceURI();
1107                        elementUri = elementUri == null ? "" : elementUri;
1108                        String elementName = element.getLocalName();
1109                        if (elementUri.equals(nameUri)
1110                            && elementName.equals(nameLocal)) {
1111                            next = element;
1112                            break;
1113                        }
1114                    }
1115                }
1116                return next != null;
1117            }
1118
1119            @Override
1120            public javax.xml.soap.Node next() {
1121                if (!hasNext()) {
1122                    throw new NoSuchElementException();
1123                }
1124                last = next;
1125                next = null;
1126                return (javax.xml.soap.Node) last;
1127            }
1128
1129            @Override
1130            public void remove() {
1131                if (last == null) {
1132                    throw new IllegalStateException();
1133                }
1134                Node target = last;
1135                last = null;
1136                removeChild(target);
1137            }
1138        };
1139    }
1140
1141    @Override
1142    public void removeContents() {
1143        Node currentChild = getFirstChild();
1144
1145        while (currentChild != null) {
1146            Node temp = currentChild.getNextSibling();
1147            if (currentChild instanceof javax.xml.soap.Node) {
1148                ((javax.xml.soap.Node) currentChild).detachNode();
1149            } else {
1150                Node parent = currentChild.getParentNode();
1151                if (parent != null) {
1152                    parent.removeChild(currentChild);
1153                }
1154
1155            }
1156            currentChild = temp;
1157        }
1158    }
1159
1160    @Override
1161    public void setEncodingStyle(String encodingStyle) throws SOAPException {
1162        if (!"".equals(encodingStyle)) {
1163            try {
1164                new URI(encodingStyle);
1165            } catch (URISyntaxException m) {
1166                log.log(
1167                    Level.SEVERE,
1168                    "SAAJ0105.impl.encoding.style.mustbe.valid.URI",
1169                    new String[] { encodingStyle });
1170                throw new IllegalArgumentException(
1171                    "Encoding style (" + encodingStyle + ") should be a valid URI");
1172            }
1173        }
1174        encodingStyleAttribute.setValue(encodingStyle);
1175        tryToFindEncodingStyleAttributeName();
1176    }
1177
1178    @Override
1179    public String getEncodingStyle() {
1180        String encodingStyle = encodingStyleAttribute.getValue();
1181        if (encodingStyle != null)
1182            return encodingStyle;
1183        String soapNamespace = getSOAPNamespace();
1184        if (soapNamespace != null) {
1185            Attr attr = getAttributeNodeNS(soapNamespace, "encodingStyle");
1186            if (attr != null) {
1187                encodingStyle = attr.getValue();
1188                try {
1189                    setEncodingStyle(encodingStyle);
1190                } catch (SOAPException se) {
1191                    // has to be ignored
1192                }
1193                return encodingStyle;
1194            }
1195        }
1196        return null;
1197    }
1198
1199    // Node methods
1200    @Override
1201    public String getValue() {
1202        javax.xml.soap.Node valueNode = getValueNode();
1203        return valueNode == null ? null : valueNode.getValue();
1204    }
1205
1206    @Override
1207    public void setValue(String value) {
1208        Node valueNode = getValueNodeStrict();
1209        if (valueNode != null) {
1210            valueNode.setNodeValue(value);
1211        } else {
1212            try {
1213                addTextNode(value);
1214            } catch (SOAPException e) {
1215                throw new RuntimeException(e.getMessage());
1216            }
1217        }
1218    }
1219
1220    protected Node getValueNodeStrict() {
1221        Node node = getFirstChild();
1222        if (node != null) {
1223            if (node.getNextSibling() == null
1224                && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
1225                return node;
1226            } else {
1227                log.severe("SAAJ0107.impl.elem.child.not.single.text");
1228                throw new IllegalStateException();
1229            }
1230        }
1231
1232        return null;
1233    }
1234
1235    protected javax.xml.soap.Node getValueNode() {
1236        Iterator<javax.xml.soap.Node> i = getChildElements();
1237        while (i.hasNext()) {
1238            Node n = i.next();
1239            if (n.getNodeType() == org.w3c.dom.Node.TEXT_NODE ||
1240                n.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE) {
1241                // TODO: Hack to fix text node split into multiple lines.
1242                normalize();
1243                // Should remove the normalization step when this gets fixed in
1244                // DOM/Xerces.
1245                return soapDocument.find(n);
1246            }
1247        }
1248        return null;
1249    }
1250
1251    @Override
1252    public void setParentElement(SOAPElement element) throws SOAPException {
1253        if (element == null) {
1254            log.severe("SAAJ0106.impl.no.null.to.parent.elem");
1255            throw new SOAPException("Cannot pass NULL to setParentElement");
1256        }
1257        element.addChildElement(this);
1258        findEncodingStyleAttributeName();
1259    }
1260
1261    protected void findEncodingStyleAttributeName() throws SOAPException {
1262        String soapNamespace = getSOAPNamespace();
1263        if (soapNamespace != null) {
1264            String soapNamespacePrefix = getNamespacePrefix(soapNamespace);
1265            if (soapNamespacePrefix != null) {
1266                setEncodingStyleNamespace(soapNamespace, soapNamespacePrefix);
1267            }
1268        }
1269    }
1270
1271    protected void setEncodingStyleNamespace(
1272        String soapNamespace,
1273        String soapNamespacePrefix)
1274        throws SOAPException {
1275        Name encodingStyleAttributeName =
1276            NameImpl.create(
1277                "encodingStyle",
1278                soapNamespacePrefix,
1279                soapNamespace);
1280        encodingStyleAttribute.setName(encodingStyleAttributeName);
1281    }
1282
1283    @Override
1284    public SOAPElement getParentElement() {
1285        Node parentNode = getParentNode();
1286        if (parentNode instanceof SOAPDocument) {
1287            return null;
1288        }
1289        return (SOAPElement) soapDocument.find(parentNode);
1290    }
1291
1292    protected String getSOAPNamespace() {
1293        String soapNamespace = null;
1294
1295        SOAPElement antecedent = this;
1296        while (antecedent != null) {
1297            Name antecedentName = antecedent.getElementName();
1298            String antecedentNamespace = antecedentName.getURI();
1299
1300            if (NameImpl.SOAP11_NAMESPACE.equals(antecedentNamespace)
1301                || NameImpl.SOAP12_NAMESPACE.equals(antecedentNamespace)) {
1302
1303                soapNamespace = antecedentNamespace;
1304                break;
1305            }
1306
1307            antecedent = antecedent.getParentElement();
1308        }
1309
1310        return soapNamespace;
1311    }
1312
1313    @Override
1314    public void detachNode() {
1315        Node parent = getParentNode();
1316        if (parent != null) {
1317            parent.removeChild(element);
1318        }
1319        encodingStyleAttribute.clearNameAndValue();
1320        // Fix for CR: 6474641
1321        //tryToFindEncodingStyleAttributeName();
1322    }
1323
1324    public void tryToFindEncodingStyleAttributeName() {
1325        try {
1326            findEncodingStyleAttributeName();
1327        } catch (SOAPException e) { /*okay to fail*/
1328        }
1329    }
1330
1331    @Override
1332    public void recycleNode() {
1333        detachNode();
1334        // TBD
1335        //  - add this to the factory so subsequent
1336        //    creations can reuse this object.
1337    }
1338
1339    class AttributeManager {
1340        Name attributeName = null;
1341        String attributeValue = null;
1342
1343        public void setName(Name newName) throws SOAPException {
1344            clearAttribute();
1345            attributeName = newName;
1346            reconcileAttribute();
1347        }
1348        public void clearName() {
1349            clearAttribute();
1350            attributeName = null;
1351        }
1352        public void setValue(String value) throws SOAPException {
1353            attributeValue = value;
1354            reconcileAttribute();
1355        }
1356        public Name getName() {
1357            return attributeName;
1358        }
1359        public String getValue() {
1360            return attributeValue;
1361        }
1362
1363        /** Note: to be used only in detachNode method */
1364        public void clearNameAndValue() {
1365            attributeName = null;
1366            attributeValue = null;
1367        }
1368
1369        private void reconcileAttribute() throws SOAPException {
1370            if (attributeName != null) {
1371                removeAttribute(attributeName);
1372                if (attributeValue != null) {
1373                    addAttribute(attributeName, attributeValue);
1374                }
1375            }
1376        }
1377        private void clearAttribute() {
1378            if (attributeName != null) {
1379                removeAttribute(attributeName);
1380            }
1381        }
1382    }
1383
1384    protected static org.w3c.dom.Attr getNamespaceAttrFrom(
1385        Element element,
1386        String prefix) {
1387        NamespaceContextIterator eachNamespace =
1388            new NamespaceContextIterator(element);
1389        while (eachNamespace.hasNext()) {
1390            org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
1391            String declaredPrefix =
1392                NameImpl.getLocalNameFromTagName(namespaceDecl.getNodeName());
1393            if (declaredPrefix.equals(prefix)) {
1394                return namespaceDecl;
1395            }
1396        }
1397        return null;
1398    }
1399
1400    protected static Iterator<Name> getAllAttributesFrom(final Element element) {
1401        final NamedNodeMap attributes = element.getAttributes();
1402
1403        return new Iterator<Name>() {
1404            int attributesLength = attributes.getLength();
1405            int attributeIndex = 0;
1406            String currentName;
1407
1408            @Override
1409            public boolean hasNext() {
1410                return attributeIndex < attributesLength;
1411            }
1412
1413            @Override
1414            public Name next() {
1415                if (!hasNext()) {
1416                    throw new NoSuchElementException();
1417                }
1418                Node current = attributes.item(attributeIndex++);
1419                currentName = current.getNodeName();
1420
1421                String prefix = NameImpl.getPrefixFromTagName(currentName);
1422                if (prefix.length() == 0) {
1423                    return NameImpl.createFromUnqualifiedName(currentName);
1424                } else {
1425                    Name attributeName =
1426                        NameImpl.createFromQualifiedName(
1427                            currentName,
1428                            current.getNamespaceURI());
1429                    return attributeName;
1430                }
1431            }
1432
1433            @Override
1434            public void remove() {
1435                if (currentName == null) {
1436                    throw new IllegalStateException();
1437                }
1438                attributes.removeNamedItem(currentName);
1439            }
1440        };
1441    }
1442
1443    protected static String getAttributeValueFrom(Element element, Name name) {
1444      return getAttributeValueFrom(
1445          element,
1446          name.getURI(),
1447          name.getLocalName(),
1448          name.getPrefix(),
1449          name.getQualifiedName());
1450    }
1451
1452    private static String getAttributeValueFrom(
1453        Element element,
1454        String uri,
1455        String localName,
1456        String prefix,
1457        String qualifiedName) {
1458
1459        String nonzeroLengthUri =
1460            (uri == null || uri.length() == 0) ? null : uri;
1461
1462        boolean mustUseGetAttributeNodeNS =  (nonzeroLengthUri != null);
1463
1464        if (mustUseGetAttributeNodeNS) {
1465
1466            if (!element.hasAttributeNS(uri, localName)) {
1467                return null;
1468            }
1469
1470            String attrValue =
1471                element.getAttributeNS(nonzeroLengthUri, localName);
1472
1473            return attrValue;
1474        }
1475
1476        Attr attribute = null;
1477        attribute = element.getAttributeNode(qualifiedName);
1478
1479        return attribute == null ? null : attribute.getValue();
1480    }
1481
1482    protected Iterator<javax.xml.soap.Node> getChildElementsFrom(final Element element) {
1483        return new Iterator<javax.xml.soap.Node>() {
1484            Node next = element.getFirstChild();
1485            Node nextNext = null;
1486            Node last = null;
1487            Node soapElement = soapDocument.findIfPresent(element);
1488
1489            @Override
1490            public boolean hasNext() {
1491                if (next != null) {
1492                    return true;
1493                }
1494                if (nextNext != null) {
1495                    next = nextNext;
1496                }
1497
1498                return next != null;
1499            }
1500
1501            @Override
1502            public javax.xml.soap.Node next() {
1503                if (hasNext()) {
1504                    last = next;
1505                    next = null;
1506
1507                    if ((soapElement instanceof ElementImpl)
1508                            && (last instanceof Element)) {
1509                        last =
1510                                ((ElementImpl) soapElement).convertToSoapElement(
1511                                        (Element) last);
1512                    }
1513
1514                    nextNext = last.getNextSibling();
1515                    return (javax.xml.soap.Node) soapDocument.findIfPresent(last);
1516                }
1517                throw new NoSuchElementException();
1518            }
1519
1520            @Override
1521            public void remove() {
1522                if (last == null) {
1523                    throw new IllegalStateException();
1524                }
1525                Node target = last;
1526                last = null;
1527                element.removeChild(target);
1528            }
1529        };
1530    }
1531
1532    public static String getQualifiedName(QName name) {
1533        String prefix = name.getPrefix();
1534        String localName = name.getLocalPart();
1535        String qualifiedName = null;
1536
1537            if (prefix != null && prefix.length() > 0) {
1538                qualifiedName = prefix + ":" + localName;
1539            } else {
1540                qualifiedName = localName;
1541            }
1542         return qualifiedName;
1543    }
1544
1545    public static String getLocalPart(String qualifiedName) {
1546        if (qualifiedName == null) {
1547            // Log
1548            throw new IllegalArgumentException("Cannot get local name for a \"null\" qualified name");
1549        }
1550
1551        int index = qualifiedName.indexOf(':');
1552        if (index < 0)
1553            return qualifiedName;
1554        else
1555            return qualifiedName.substring(index + 1);
1556    }
1557
1558    public static String getPrefix(String qualifiedName) {
1559        if (qualifiedName == null) {
1560            // Log
1561            throw new IllegalArgumentException("Cannot get prefix for a  \"null\" qualified name");
1562        }
1563
1564        int index = qualifiedName.indexOf(':');
1565        if (index < 0)
1566            return "";
1567        else
1568            return qualifiedName.substring(0, index);
1569    }
1570
1571    protected boolean isNamespaceQualified(Name name) {
1572        return !"".equals(name.getURI());
1573    }
1574
1575    protected boolean isNamespaceQualified(QName name) {
1576        return !"".equals(name.getNamespaceURI());
1577    }
1578
1579    //TODO: This is a temporary SAAJ workaround for optimizing XWS
1580    // should be removed once the corresponding JAXP bug is fixed
1581    // It appears the bug will be fixed in JAXP 1.4 (not by Appserver 9 timeframe)
1582    @Override
1583    public void setAttributeNS(
1584        String namespaceURI,String qualifiedName, String value) {
1585        int index = qualifiedName.indexOf(':');
1586        String localName;
1587        if (index < 0)
1588            localName = qualifiedName;
1589        else
1590            localName = qualifiedName.substring(index + 1);
1591
1592        // Workaround for bug 6467808 - This needs to be fixed in JAXP
1593
1594        // Rolling back this fix, this is a wrong fix, infact its causing other regressions in JAXWS tck and
1595        // other tests, because of this change the namespace declarations on soapenv:Fault element are never
1596        // picked up. The fix for bug 6467808 should be in JAXP.
1597//        if(elementQName.getLocalPart().equals("Fault") &&
1598//                (SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE.equals(value) ||
1599//                SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE.equals(value)))
1600//            return;
1601
1602        element.setAttributeNS(namespaceURI,qualifiedName,value);
1603        //String tmpLocalName = this.getLocalName();
1604        String tmpURI = this.getNamespaceURI();
1605        boolean isIDNS = false;
1606        if( tmpURI != null && (tmpURI.equals(DSIG_NS) || tmpURI.equals(XENC_NS))){
1607            isIDNS = true;
1608        }
1609        //No need to check for Signature/encryption element
1610        //just check for namespace.
1611        if(localName.equals("Id")){
1612            if(namespaceURI == null || namespaceURI.equals("")){
1613                setIdAttribute(localName,true);
1614            }else if(isIDNS || WSU_NS.equals(namespaceURI)){
1615                setIdAttributeNS(namespaceURI,localName,true);
1616            }
1617        }
1618
1619    }
1620
1621    @Override
1622    public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
1623        element.removeAttributeNS(namespaceURI, localName);
1624    }
1625
1626    @Override
1627    public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
1628        return element.getAttributeNodeNS(namespaceURI, localName);
1629    }
1630
1631    @Override
1632    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
1633        return element.setAttributeNodeNS(newAttr);
1634    }
1635
1636    @Override
1637    public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {
1638        return new NodeListImpl(soapDocument, element.getElementsByTagNameNS(namespaceURI, localName));
1639    }
1640
1641    @Override
1642    public boolean hasAttribute(String name) {
1643        return element.hasAttribute(name);
1644    }
1645
1646    @Override
1647    public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
1648        return element.hasAttributeNS(namespaceURI, localName);
1649    }
1650
1651    @Override
1652    public TypeInfo getSchemaTypeInfo() {
1653        return element.getSchemaTypeInfo();
1654    }
1655
1656    @Override
1657    public void setIdAttribute(String name, boolean isId) throws DOMException {
1658        element.setIdAttribute(name, isId);
1659    }
1660
1661    @Override
1662    public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
1663        element.setIdAttributeNS(namespaceURI, localName, isId);
1664    }
1665
1666    @Override
1667    public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
1668        element.setIdAttributeNode(idAttr, isId);
1669    }
1670
1671    @Override
1672    public String getNodeName() {
1673        return element.getNodeName();
1674    }
1675
1676    @Override
1677    public String getNodeValue() throws DOMException {
1678        return element.getNodeValue();
1679    }
1680
1681    @Override
1682    public void setNodeValue(String nodeValue) throws DOMException {
1683        element.setNodeValue(nodeValue);
1684    }
1685
1686    @Override
1687    public short getNodeType() {
1688        return element.getNodeType();
1689    }
1690
1691    @Override
1692    public Node getParentNode() {
1693        return soapDocument.find(element.getParentNode());
1694    }
1695
1696    @Override
1697    public NodeList getChildNodes() {
1698        return new NodeListImpl(soapDocument, element.getChildNodes());
1699    }
1700
1701    @Override
1702    public Node getFirstChild() {
1703        return soapDocument.findIfPresent(element.getFirstChild());
1704    }
1705
1706    @Override
1707    public Node getLastChild() {
1708        return soapDocument.findIfPresent(element.getLastChild());
1709    }
1710
1711    @Override
1712    public Node getPreviousSibling() {
1713        return soapDocument.findIfPresent(element.getPreviousSibling());
1714    }
1715
1716    @Override
1717    public Node getNextSibling() {
1718        return soapDocument.findIfPresent(element.getNextSibling());
1719    }
1720
1721    @Override
1722    public NamedNodeMap getAttributes() {
1723        return new NamedNodeMapImpl(element.getAttributes(), soapDocument);
1724    }
1725
1726    public Element getDomElement() {
1727        return element;
1728    }
1729
1730    public SOAPDocumentImpl getSoapDocument() {
1731        return soapDocument;
1732    }
1733}
1734