1 /*
   2  * Copyright (c) 1997, 2014, 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 
  26 package com.sun.xml.internal.messaging.saaj.soap.impl;
  27 
  28 import java.net.URI;
  29 import java.net.URISyntaxException;
  30 import java.util.*;
  31 import java.util.logging.Level;
  32 import java.util.logging.Logger;
  33 
  34 import javax.xml.namespace.QName;
  35 import javax.xml.soap.*;
  36 
  37 import org.w3c.dom.*;
  38 import org.w3c.dom.Node;
  39 
  40 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  41 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument;
  42 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
  43 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  44 import com.sun.xml.internal.messaging.saaj.util.*;
  45 
  46 public class ElementImpl
  47     extends com.sun.org.apache.xerces.internal.dom.ElementNSImpl
  48     implements SOAPElement, SOAPBodyElement {
  49 
  50     public static final String DSIG_NS = "http://www.w3.org/2000/09/xmldsig#".intern();
  51     public static final String XENC_NS = "http://www.w3.org/2001/04/xmlenc#".intern();
  52     public static final String WSU_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd".intern();
  53 
  54     private transient AttributeManager encodingStyleAttribute = new AttributeManager();
  55 
  56     protected QName elementQName;
  57 
  58     protected static final Logger log =
  59         Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN,
  60                          "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings");
  61 
  62     /**
  63      * XML Information Set REC
  64      * all namespace attributes (including those named xmlns,
  65      * whose [prefix] property has no value) have a namespace URI of http://www.w3.org/2000/xmlns/
  66      */
  67     public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/".intern();
  68 
  69     /**
  70      * The XML Namespace ("http://www.w3.org/XML/1998/namespace"). This is
  71      * the Namespace URI that is automatically mapped to the "xml" prefix.
  72      */
  73     public final static String XML_URI = "http://www.w3.org/XML/1998/namespace".intern();
  74 
  75     public ElementImpl(SOAPDocumentImpl ownerDoc, Name name) {
  76         super(
  77             ownerDoc,
  78             name.getURI(),
  79             name.getQualifiedName(),
  80             name.getLocalName());
  81         elementQName = NameImpl.convertToQName(name);
  82     }
  83 
  84     public ElementImpl(SOAPDocumentImpl ownerDoc, QName name) {
  85         super(
  86             ownerDoc,
  87             name.getNamespaceURI(),
  88             getQualifiedName(name),
  89             name.getLocalPart());
  90         elementQName = name;
  91     }
  92 
  93     public ElementImpl(
  94         SOAPDocumentImpl ownerDoc,
  95         String uri,
  96         String qualifiedName) {
  97 
  98         super(ownerDoc, uri, qualifiedName);
  99         elementQName =
 100             new QName(uri, getLocalPart(qualifiedName), getPrefix(qualifiedName));
 101     }
 102 
 103     public void ensureNamespaceIsDeclared(String prefix, String uri) {
 104         String alreadyDeclaredUri = getNamespaceURI(prefix);
 105         if (alreadyDeclaredUri == null || !alreadyDeclaredUri.equals(uri)) {
 106             try {
 107                 addNamespaceDeclaration(prefix, uri);
 108             } catch (SOAPException e) { /*ignore*/
 109             }
 110         }
 111     }
 112 
 113     public Document getOwnerDocument() {
 114         Document doc = super.getOwnerDocument();
 115         if (doc instanceof SOAPDocument)
 116             return ((SOAPDocument) doc).getDocument();
 117         else
 118             return doc;
 119     }
 120 
 121     public SOAPElement addChildElement(Name name) throws SOAPException {
 122         return  addElement(name);
 123     }
 124 
 125     public SOAPElement addChildElement(QName qname) throws SOAPException {
 126         return  addElement(qname);
 127     }
 128 
 129     public SOAPElement addChildElement(String localName) throws SOAPException {
 130         return (SOAPElement) addChildElement(
 131             NameImpl.createFromUnqualifiedName(localName));
 132     }
 133 
 134     public SOAPElement addChildElement(String localName, String prefix)
 135         throws SOAPException {
 136         String uri = getNamespaceURI(prefix);
 137         if (uri == null) {
 138             log.log(
 139                 Level.SEVERE,
 140                 "SAAJ0101.impl.parent.of.body.elem.mustbe.body",
 141                 new String[] { prefix });
 142             throw new SOAPExceptionImpl(
 143                 "Unable to locate namespace for prefix " + prefix);
 144         }
 145         return addChildElement(localName, prefix, uri);
 146     }
 147 
 148     public String getNamespaceURI(String prefix) {
 149 
 150         if ("xmlns".equals(prefix)) {
 151             return XMLNS_URI;
 152         }
 153 
 154         if("xml".equals(prefix)) {
 155             return XML_URI;
 156         }
 157 
 158         if ("".equals(prefix)) {
 159 
 160             org.w3c.dom.Node currentAncestor = this;
 161             while (currentAncestor != null &&
 162                    !(currentAncestor instanceof Document)) {
 163 
 164                 if (currentAncestor instanceof ElementImpl) {
 165                     QName name = ((ElementImpl) currentAncestor).getElementQName();
 166                     /*
 167                     if (prefix.equals(name.getPrefix())) {
 168                         String uri = name.getNamespaceURI();
 169                         if ("".equals(uri)) {
 170                             return null;
 171                         }
 172                         else {
 173                             return uri;
 174                         }
 175                     }*/
 176                     if (((Element) currentAncestor).hasAttributeNS(
 177                             XMLNS_URI, "xmlns")) {
 178 
 179                         String uri =
 180                             ((Element) currentAncestor).getAttributeNS(
 181                                 XMLNS_URI, "xmlns");
 182                         if ("".equals(uri))
 183                             return null;
 184                         else {
 185                             return uri;
 186                         }
 187                     }
 188                 }
 189                 currentAncestor = currentAncestor.getParentNode();
 190             }
 191 
 192         } else if (prefix != null) {
 193             // Find if there's an ancester whose name contains this prefix
 194             org.w3c.dom.Node currentAncestor = this;
 195 
 196 //            String uri = currentAncestor.lookupNamespaceURI(prefix);
 197 //            return uri;
 198             while (currentAncestor != null &&
 199                    !(currentAncestor instanceof Document)) {
 200 
 201                /* if (prefix.equals(currentAncestor.getPrefix())) {
 202                     String uri = currentAncestor.getNamespaceURI();
 203                     // this is because the javadoc says getNamespaceURI() is not a computed value
 204                     // and URI for a non-empty prefix cannot be null
 205                     if (uri != null)
 206                         return uri;
 207                 }*/
 208                 //String uri = currentAncestor.lookupNamespaceURI(prefix);
 209                 //if (uri != null) {
 210                 //    return uri;
 211                 //}
 212 
 213                 if (((Element) currentAncestor).hasAttributeNS(
 214                         XMLNS_URI, prefix)) {
 215                     return ((Element) currentAncestor).getAttributeNS(
 216                                XMLNS_URI, prefix);
 217                 }
 218 
 219                 currentAncestor = currentAncestor.getParentNode();
 220             }
 221         }
 222 
 223         return null;
 224     }
 225 
 226     public SOAPElement setElementQName(QName newName) throws SOAPException {
 227         ElementImpl copy =
 228             new ElementImpl((SOAPDocumentImpl) getOwnerDocument(), newName);
 229         return replaceElementWithSOAPElement(this,copy);
 230     }
 231 
 232     public QName createQName(String localName, String prefix)
 233         throws SOAPException {
 234         String uri = getNamespaceURI(prefix);
 235         if (uri == null) {
 236             log.log(Level.SEVERE, "SAAJ0102.impl.cannot.locate.ns",
 237                     new Object[] {prefix});
 238             throw new SOAPException("Unable to locate namespace for prefix "
 239                                     + prefix);
 240         }
 241         return new QName(uri, localName, prefix);
 242     }
 243 
 244     public String getNamespacePrefix(String uri) {
 245 
 246         NamespaceContextIterator eachNamespace = getNamespaceContextNodes();
 247         while (eachNamespace.hasNext()) {
 248             org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
 249             if (namespaceDecl.getNodeValue().equals(uri)) {
 250                 String candidatePrefix = namespaceDecl.getLocalName();
 251                 if ("xmlns".equals(candidatePrefix))
 252                     return "";
 253                 else
 254                     return candidatePrefix;
 255             }
 256         }
 257 
 258         // Find if any of the ancestors' name has this uri
 259         org.w3c.dom.Node currentAncestor = this;
 260         while (currentAncestor != null &&
 261                !(currentAncestor instanceof Document)) {
 262 
 263             if (uri.equals(currentAncestor.getNamespaceURI()))
 264                 return currentAncestor.getPrefix();
 265             currentAncestor = currentAncestor.getParentNode();
 266         }
 267 
 268         return null;
 269     }
 270 
 271     protected org.w3c.dom.Attr getNamespaceAttr(String prefix) {
 272         NamespaceContextIterator eachNamespace = getNamespaceContextNodes();
 273         if (!"".equals(prefix))
 274             prefix = ":"+prefix;
 275         while (eachNamespace.hasNext()) {
 276             org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
 277             if (!"".equals(prefix)) {
 278                 if (namespaceDecl.getNodeName().endsWith(prefix))
 279                     return namespaceDecl;
 280             } else {
 281                 if (namespaceDecl.getNodeName().equals("xmlns"))
 282                     return namespaceDecl;
 283             }
 284         }
 285         return null;
 286     }
 287 
 288     public NamespaceContextIterator getNamespaceContextNodes() {
 289         return getNamespaceContextNodes(true);
 290     }
 291 
 292     public NamespaceContextIterator getNamespaceContextNodes(boolean traverseStack) {
 293         return new NamespaceContextIterator(this, traverseStack);
 294     }
 295 
 296     public SOAPElement addChildElement(
 297         String localName,
 298         String prefix,
 299         String uri)
 300         throws SOAPException {
 301 
 302         SOAPElement newElement = createElement(NameImpl.create(localName, prefix, uri));
 303         addNode(newElement);
 304         return convertToSoapElement(newElement);
 305     }
 306 
 307     public SOAPElement addChildElement(SOAPElement element)
 308         throws SOAPException {
 309 
 310         // check if Element falls in SOAP 1.1 or 1.2 namespace.
 311         String elementURI = element.getElementName().getURI();
 312         String localName = element.getLocalName();
 313 
 314         if ((SOAPConstants.URI_NS_SOAP_ENVELOPE).equals(elementURI)
 315             || (SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE).equals(elementURI)) {
 316 
 317 
 318             if ("Envelope".equalsIgnoreCase(localName) ||
 319                 "Header".equalsIgnoreCase(localName) || "Body".equalsIgnoreCase(localName)) {
 320                 log.severe("SAAJ0103.impl.cannot.add.fragements");
 321                 throw new SOAPExceptionImpl(
 322                     "Cannot add fragments which contain elements "
 323                         + "which are in the SOAP namespace");
 324             }
 325 
 326             if ("Fault".equalsIgnoreCase(localName) && !"Body".equalsIgnoreCase(this.getLocalName())) {
 327                 log.severe("SAAJ0154.impl.adding.fault.to.nonbody");
 328                 throw new SOAPExceptionImpl("Cannot add a SOAPFault as a child of " + this.getLocalName());
 329             }
 330 
 331             if ("Detail".equalsIgnoreCase(localName) && !"Fault".equalsIgnoreCase(this.getLocalName())) {
 332                 log.severe("SAAJ0155.impl.adding.detail.nonfault");
 333                 throw new SOAPExceptionImpl("Cannot add a Detail as a child of " + this.getLocalName());
 334             }
 335 
 336             if ("Fault".equalsIgnoreCase(localName)) {
 337                // if body is not empty throw an exception
 338                if (!elementURI.equals(this.getElementName().getURI())) {
 339                    log.severe("SAAJ0158.impl.version.mismatch.fault");
 340                    throw new SOAPExceptionImpl("SOAP Version mismatch encountered when trying to add SOAPFault to SOAPBody");
 341                }
 342                Iterator it = this.getChildElements();
 343                if (it.hasNext()) {
 344                    log.severe("SAAJ0156.impl.adding.fault.error");
 345                    throw new SOAPExceptionImpl("Cannot add SOAPFault as a child of a non-Empty SOAPBody");
 346                }
 347             }
 348         }
 349 
 350         // preserve the encodingStyle attr as it may get lost in the import
 351         String encodingStyle = element.getEncodingStyle();
 352 
 353         ElementImpl importedElement = (ElementImpl) importElement(element);
 354         addNode(importedElement);
 355 
 356         if (encodingStyle != null)
 357             importedElement.setEncodingStyle(encodingStyle);
 358 
 359         return convertToSoapElement(importedElement);
 360     }
 361 
 362     protected Element importElement(Element element) {
 363         Document document = getOwnerDocument();
 364         Document oldDocument = element.getOwnerDocument();
 365         if (!oldDocument.equals(document)) {
 366             return (Element) document.importNode(element, true);
 367         } else {
 368             return element;
 369         }
 370     }
 371 
 372     protected SOAPElement addElement(Name name) throws SOAPException {
 373         SOAPElement newElement = createElement(name);
 374         addNode(newElement);
 375         return circumventBug5034339(newElement);
 376     }
 377 
 378     protected SOAPElement addElement(QName name) throws SOAPException {
 379         SOAPElement newElement = createElement(name);
 380         addNode(newElement);
 381         return circumventBug5034339(newElement);
 382     }
 383 
 384     protected SOAPElement createElement(Name name) {
 385 
 386         if (isNamespaceQualified(name)) {
 387             return (SOAPElement)
 388                 getOwnerDocument().createElementNS(
 389                                        name.getURI(),
 390                                        name.getQualifiedName());
 391         } else {
 392             return (SOAPElement)
 393                 getOwnerDocument().createElement(name.getQualifiedName());
 394         }
 395     }
 396 
 397     protected SOAPElement createElement(QName name) {
 398 
 399         if (isNamespaceQualified(name)) {
 400             return (SOAPElement)
 401                 getOwnerDocument().createElementNS(
 402                                        name.getNamespaceURI(),
 403                                        getQualifiedName(name));
 404         } else {
 405             return (SOAPElement)
 406                 getOwnerDocument().createElement(getQualifiedName(name));
 407         }
 408     }
 409 
 410     protected void addNode(org.w3c.dom.Node newElement) throws SOAPException {
 411         insertBefore(newElement, null);
 412 
 413         if (getOwnerDocument() instanceof DocumentFragment)
 414             return;
 415 
 416         if (newElement instanceof ElementImpl) {
 417             ElementImpl element = (ElementImpl) newElement;
 418             QName elementName = element.getElementQName();
 419             if (!"".equals(elementName.getNamespaceURI())) {
 420                 element.ensureNamespaceIsDeclared(
 421                     elementName.getPrefix(), elementName.getNamespaceURI());
 422             }
 423         }
 424 
 425     }
 426 
 427     Element getFirstChildElement() {
 428         Node child = getFirstChild();
 429         while (child != null) {
 430             if (child instanceof Element) {
 431                 return ((Element) child);
 432             }
 433             child = child.getNextSibling();
 434         }
 435         return null;
 436     }
 437 
 438     protected SOAPElement findChild(NameImpl name) {
 439         Node eachChild = getFirstChild();
 440         while (eachChild != null) {
 441             if (eachChild instanceof SOAPElement) {
 442                 SOAPElement eachChildSoap = (SOAPElement) eachChild;
 443                 if (eachChildSoap.getElementName().equals(name)) {
 444                     return eachChildSoap;
 445                 }
 446             }
 447             eachChild = eachChild.getNextSibling();
 448         }
 449         return null;
 450     }
 451 
 452     protected SOAPElement findAndConvertChildElement(NameImpl name) {
 453         Iterator eachChild = getChildElementNodes();
 454         while (eachChild.hasNext()) {
 455             SOAPElement child = (SOAPElement) eachChild.next();
 456             if (child.getElementName().equals(name)) {
 457                 return child;
 458             }
 459         }
 460 
 461         return null;
 462     }
 463 
 464     public SOAPElement addTextNode(String text) throws SOAPException {
 465         if (text.startsWith(CDATAImpl.cdataUC)
 466             || text.startsWith(CDATAImpl.cdataLC))
 467             return addCDATA(
 468                 text.substring(CDATAImpl.cdataUC.length(), text.length() - 3));
 469         return addText(text);
 470     }
 471 
 472     protected SOAPElement addCDATA(String text) throws SOAPException {
 473         org.w3c.dom.Text cdata =
 474             (org.w3c.dom.Text) getOwnerDocument().createCDATASection(text);
 475         addNode(cdata);
 476         return this;
 477     }
 478 
 479     protected SOAPElement addText(String text) throws SOAPException {
 480         org.w3c.dom.Text textNode =
 481             (org.w3c.dom.Text) getOwnerDocument().createTextNode(text);
 482         addNode(textNode);
 483         return this;
 484     }
 485 
 486     public SOAPElement addAttribute(Name name, String value)
 487         throws SOAPException {
 488         addAttributeBare(name, value);
 489         if (!"".equals(name.getURI())) {
 490             ensureNamespaceIsDeclared(name.getPrefix(), name.getURI());
 491         }
 492         return this;
 493     }
 494 
 495     public SOAPElement addAttribute(QName qname, String value)
 496         throws SOAPException {
 497         addAttributeBare(qname, value);
 498         if (!"".equals(qname.getNamespaceURI())) {
 499             ensureNamespaceIsDeclared(qname.getPrefix(), qname.getNamespaceURI());
 500         }
 501         return this;
 502     }
 503 
 504     private void addAttributeBare(Name name, String value) {
 505         addAttributeBare(
 506             name.getURI(),
 507             name.getPrefix(),
 508             name.getQualifiedName(),
 509             value);
 510     }
 511     private void addAttributeBare(QName name, String value) {
 512         addAttributeBare(
 513             name.getNamespaceURI(),
 514             name.getPrefix(),
 515             getQualifiedName(name),
 516             value);
 517     }
 518 
 519     private void addAttributeBare(
 520         String uri,
 521         String prefix,
 522         String qualifiedName,
 523         String value) {
 524 
 525         uri = uri.length() == 0 ? null : uri;
 526         if (qualifiedName.equals("xmlns")) {
 527             uri = XMLNS_URI;
 528         }
 529 
 530         if (uri == null) {
 531             setAttribute(qualifiedName, value);
 532         } else {
 533             setAttributeNS(uri, qualifiedName, value);
 534         }
 535     }
 536 
 537     public SOAPElement addNamespaceDeclaration(String prefix, String uri)
 538         throws SOAPException {
 539         if (prefix.length() > 0) {
 540             setAttributeNS(XMLNS_URI, "xmlns:" + prefix, uri);
 541         } else {
 542             setAttributeNS(XMLNS_URI, "xmlns", uri);
 543         }
 544         //Fix for CR:6474641
 545         //tryToFindEncodingStyleAttributeName();
 546         return this;
 547     }
 548 
 549     public String getAttributeValue(Name name) {
 550         return getAttributeValueFrom(this, name);
 551     }
 552 
 553     public String getAttributeValue(QName qname) {
 554         return getAttributeValueFrom(
 555                    this,
 556                    qname.getNamespaceURI(),
 557                    qname.getLocalPart(),
 558                    qname.getPrefix(),
 559                    getQualifiedName(qname));
 560     }
 561 
 562     public Iterator getAllAttributes() {
 563         Iterator i = getAllAttributesFrom(this);
 564         ArrayList list = new ArrayList();
 565         while (i.hasNext()) {
 566             Name name = (Name) i.next();
 567             if (!"xmlns".equalsIgnoreCase(name.getPrefix()))
 568                 list.add(name);
 569         }
 570         return list.iterator();
 571     }
 572 
 573     public Iterator getAllAttributesAsQNames() {
 574         Iterator i = getAllAttributesFrom(this);
 575         ArrayList list = new ArrayList();
 576         while (i.hasNext()) {
 577             Name name = (Name) i.next();
 578             if (!"xmlns".equalsIgnoreCase(name.getPrefix())) {
 579                 list.add(NameImpl.convertToQName(name));
 580             }
 581         }
 582         return list.iterator();
 583     }
 584 
 585 
 586     public Iterator getNamespacePrefixes() {
 587         return doGetNamespacePrefixes(false);
 588     }
 589 
 590     public Iterator getVisibleNamespacePrefixes() {
 591         return doGetNamespacePrefixes(true);
 592     }
 593 
 594     protected Iterator doGetNamespacePrefixes(final boolean deep) {
 595         return new Iterator() {
 596             String next = null;
 597             String last = null;
 598             NamespaceContextIterator eachNamespace =
 599                 getNamespaceContextNodes(deep);
 600 
 601             void findNext() {
 602                 while (next == null && eachNamespace.hasNext()) {
 603                     String attributeKey =
 604                         eachNamespace.nextNamespaceAttr().getNodeName();
 605                     if (attributeKey.startsWith("xmlns:")) {
 606                         next = attributeKey.substring("xmlns:".length());
 607                     }
 608                 }
 609             }
 610 
 611             public boolean hasNext() {
 612                 findNext();
 613                 return next != null;
 614             }
 615 
 616             public Object next() {
 617                 findNext();
 618                 if (next == null) {
 619                     throw new NoSuchElementException();
 620                 }
 621 
 622                 last = next;
 623                 next = null;
 624                 return last;
 625             }
 626 
 627             public void remove() {
 628                 if (last == null) {
 629                     throw new IllegalStateException();
 630                 }
 631                 eachNamespace.remove();
 632                 next = null;
 633                 last = null;
 634             }
 635         };
 636     }
 637 
 638     public Name getElementName() {
 639         return NameImpl.convertToName(elementQName);
 640     }
 641 
 642     public QName getElementQName() {
 643         return elementQName;
 644     }
 645 
 646     public boolean removeAttribute(Name name) {
 647         return removeAttribute(name.getURI(), name.getLocalName());
 648     }
 649 
 650     public boolean removeAttribute(QName name) {
 651         return removeAttribute(name.getNamespaceURI(), name.getLocalPart());
 652     }
 653 
 654     private boolean removeAttribute(String uri, String localName) {
 655         String nonzeroLengthUri =
 656             (uri == null || uri.length() == 0) ? null : uri;
 657         org.w3c.dom.Attr attribute =
 658             getAttributeNodeNS(nonzeroLengthUri, localName);
 659         if (attribute == null) {
 660             return false;
 661         }
 662         removeAttributeNode(attribute);
 663         return true;
 664     }
 665 
 666     public boolean removeNamespaceDeclaration(String prefix) {
 667         org.w3c.dom.Attr declaration = getNamespaceAttr(prefix);
 668         if (declaration == null) {
 669             return false;
 670         }
 671         try {
 672             removeAttributeNode(declaration);
 673         } catch (DOMException de) {
 674             // ignore
 675         }
 676         return true;
 677     }
 678 
 679     public Iterator getChildElements() {
 680         return getChildElementsFrom(this);
 681     }
 682 
 683     protected SOAPElement convertToSoapElement(Element element) {
 684         if (element instanceof SOAPElement) {
 685             return (SOAPElement) element;
 686         } else {
 687             return replaceElementWithSOAPElement(
 688                 element,
 689                 (ElementImpl) createElement(NameImpl.copyElementName(element)));
 690         }
 691     }
 692 
 693     protected static SOAPElement replaceElementWithSOAPElement(
 694         Element element,
 695         ElementImpl copy) {
 696 
 697         Iterator eachAttribute = getAllAttributesFrom(element);
 698         while (eachAttribute.hasNext()) {
 699             Name name = (Name) eachAttribute.next();
 700             copy.addAttributeBare(name, getAttributeValueFrom(element, name));
 701         }
 702 
 703         Iterator eachChild = getChildElementsFrom(element);
 704         while (eachChild.hasNext()) {
 705             Node nextChild = (Node) eachChild.next();
 706             copy.insertBefore(nextChild, null);
 707         }
 708 
 709         Node parent = element.getParentNode();
 710         if (parent != null) {
 711             parent.replaceChild(copy, element);
 712         } // XXX else throw an exception?
 713 
 714         return copy;
 715     }
 716 
 717     protected Iterator getChildElementNodes() {
 718         return new Iterator() {
 719             Iterator eachNode = getChildElements();
 720             Node next = null;
 721             Node last = null;
 722 
 723             public boolean hasNext() {
 724                 if (next == null) {
 725                     while (eachNode.hasNext()) {
 726                         Node node = (Node) eachNode.next();
 727                         if (node instanceof SOAPElement) {
 728                             next = node;
 729                             break;
 730                         }
 731                     }
 732                 }
 733                 return next != null;
 734             }
 735 
 736             public Object next() {
 737                 if (hasNext()) {
 738                     last = next;
 739                     next = null;
 740                     return last;
 741                 }
 742                 throw new NoSuchElementException();
 743             }
 744 
 745             public void remove() {
 746                 if (last == null) {
 747                     throw new IllegalStateException();
 748                 }
 749                 Node target = last;
 750                 last = null;
 751                 removeChild(target);
 752             }
 753         };
 754     }
 755 
 756     public Iterator getChildElements(final Name name) {
 757        return getChildElements(name.getURI(), name.getLocalName());
 758     }
 759 
 760     public Iterator getChildElements(final QName qname) {
 761         return getChildElements(qname.getNamespaceURI(), qname.getLocalPart());
 762     }
 763 
 764     private Iterator getChildElements(final String nameUri, final String nameLocal) {
 765         return new Iterator() {
 766             Iterator eachElement = getChildElementNodes();
 767             Node next = null;
 768             Node last = null;
 769 
 770             public boolean hasNext() {
 771                 if (next == null) {
 772                     while (eachElement.hasNext()) {
 773                         Node element = (Node) eachElement.next();
 774                         String elementUri = element.getNamespaceURI();
 775                         elementUri = elementUri == null ? "" : elementUri;
 776                         String elementName = element.getLocalName();
 777                         if (elementUri.equals(nameUri)
 778                             && elementName.equals(nameLocal)) {
 779                             next = element;
 780                             break;
 781                         }
 782                     }
 783                 }
 784                 return next != null;
 785             }
 786 
 787             public Object next() {
 788                 if (!hasNext()) {
 789                     throw new NoSuchElementException();
 790                 }
 791                 last = next;
 792                 next = null;
 793                 return last;
 794             }
 795 
 796             public void remove() {
 797                 if (last == null) {
 798                     throw new IllegalStateException();
 799                 }
 800                 Node target = last;
 801                 last = null;
 802                 removeChild(target);
 803             }
 804         };
 805     }
 806 
 807     public void removeContents() {
 808         Node currentChild = getFirstChild();
 809 
 810         while (currentChild != null) {
 811             Node temp = currentChild.getNextSibling();
 812             if (currentChild instanceof javax.xml.soap.Node) {
 813                 ((javax.xml.soap.Node) currentChild).detachNode();
 814             } else {
 815                 Node parent = currentChild.getParentNode();
 816                 if (parent != null) {
 817                     parent.removeChild(currentChild);
 818                 }
 819 
 820             }
 821             currentChild = temp;
 822         }
 823     }
 824 
 825     public void setEncodingStyle(String encodingStyle) throws SOAPException {
 826         if (!"".equals(encodingStyle)) {
 827             try {
 828                 new URI(encodingStyle);
 829             } catch (URISyntaxException m) {
 830                 log.log(
 831                     Level.SEVERE,
 832                     "SAAJ0105.impl.encoding.style.mustbe.valid.URI",
 833                     new String[] { encodingStyle });
 834                 throw new IllegalArgumentException(
 835                     "Encoding style (" + encodingStyle + ") should be a valid URI");
 836             }
 837         }
 838         encodingStyleAttribute.setValue(encodingStyle);
 839         tryToFindEncodingStyleAttributeName();
 840     }
 841 
 842     public String getEncodingStyle() {
 843         String encodingStyle = encodingStyleAttribute.getValue();
 844         if (encodingStyle != null)
 845             return encodingStyle;
 846         String soapNamespace = getSOAPNamespace();
 847         if (soapNamespace != null) {
 848             Attr attr = getAttributeNodeNS(soapNamespace, "encodingStyle");
 849             if (attr != null) {
 850                 encodingStyle = attr.getValue();
 851                 try {
 852                     setEncodingStyle(encodingStyle);
 853                 } catch (SOAPException se) {
 854                     // has to be ignored
 855                 }
 856                 return encodingStyle;
 857             }
 858         }
 859         return null;
 860     }
 861 
 862     // Node methods
 863     public String getValue() {
 864         javax.xml.soap.Node valueNode = getValueNode();
 865         return valueNode == null ? null : valueNode.getValue();
 866     }
 867 
 868     public void setValue(String value) {
 869         Node valueNode = getValueNodeStrict();
 870         if (valueNode != null) {
 871             valueNode.setNodeValue(value);
 872         } else {
 873             try {
 874                 addTextNode(value);
 875             } catch (SOAPException e) {
 876                 throw new RuntimeException(e.getMessage());
 877             }
 878         }
 879     }
 880 
 881     protected Node getValueNodeStrict() {
 882         Node node = getFirstChild();
 883         if (node != null) {
 884             if (node.getNextSibling() == null
 885                 && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
 886                 return node;
 887             } else {
 888                 log.severe("SAAJ0107.impl.elem.child.not.single.text");
 889                 throw new IllegalStateException();
 890             }
 891         }
 892 
 893         return null;
 894     }
 895 
 896     protected javax.xml.soap.Node getValueNode() {
 897         Iterator i = getChildElements();
 898         while (i.hasNext()) {
 899             javax.xml.soap.Node n = (javax.xml.soap.Node) i.next();
 900             if (n.getNodeType() == org.w3c.dom.Node.TEXT_NODE ||
 901                 n.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE) {
 902                 // TODO: Hack to fix text node split into multiple lines.
 903                 normalize();
 904                 // Should remove the normalization step when this gets fixed in
 905                 // DOM/Xerces.
 906                 return (javax.xml.soap.Node) n;
 907             }
 908         }
 909         return null;
 910     }
 911 
 912     public void setParentElement(SOAPElement element) throws SOAPException {
 913         if (element == null) {
 914             log.severe("SAAJ0106.impl.no.null.to.parent.elem");
 915             throw new SOAPException("Cannot pass NULL to setParentElement");
 916         }
 917         element.addChildElement(this);
 918         findEncodingStyleAttributeName();
 919     }
 920 
 921     protected void findEncodingStyleAttributeName() throws SOAPException {
 922         String soapNamespace = getSOAPNamespace();
 923         if (soapNamespace != null) {
 924             String soapNamespacePrefix = getNamespacePrefix(soapNamespace);
 925             if (soapNamespacePrefix != null) {
 926                 setEncodingStyleNamespace(soapNamespace, soapNamespacePrefix);
 927             }
 928         }
 929     }
 930 
 931     protected void setEncodingStyleNamespace(
 932         String soapNamespace,
 933         String soapNamespacePrefix)
 934         throws SOAPException {
 935         Name encodingStyleAttributeName =
 936             NameImpl.create(
 937                 "encodingStyle",
 938                 soapNamespacePrefix,
 939                 soapNamespace);
 940         encodingStyleAttribute.setName(encodingStyleAttributeName);
 941     }
 942 
 943     public SOAPElement getParentElement() {
 944         Node parentNode = getParentNode();
 945         if (parentNode instanceof SOAPDocument) {
 946             return null;
 947         }
 948         return (SOAPElement) parentNode;
 949     }
 950 
 951     protected String getSOAPNamespace() {
 952         String soapNamespace = null;
 953 
 954         SOAPElement antecedent = this;
 955         while (antecedent != null) {
 956             Name antecedentName = antecedent.getElementName();
 957             String antecedentNamespace = antecedentName.getURI();
 958 
 959             if (NameImpl.SOAP11_NAMESPACE.equals(antecedentNamespace)
 960                 || NameImpl.SOAP12_NAMESPACE.equals(antecedentNamespace)) {
 961 
 962                 soapNamespace = antecedentNamespace;
 963                 break;
 964             }
 965 
 966             antecedent = antecedent.getParentElement();
 967         }
 968 
 969         return soapNamespace;
 970     }
 971 
 972     public void detachNode() {
 973         Node parent = getParentNode();
 974         if (parent != null) {
 975             parent.removeChild(this);
 976         }
 977         encodingStyleAttribute.clearNameAndValue();
 978         // Fix for CR: 6474641
 979         //tryToFindEncodingStyleAttributeName();
 980     }
 981 
 982     public void tryToFindEncodingStyleAttributeName() {
 983         try {
 984             findEncodingStyleAttributeName();
 985         } catch (SOAPException e) { /*okay to fail*/
 986         }
 987     }
 988 
 989     public void recycleNode() {
 990         detachNode();
 991         // TBD
 992         //  - add this to the factory so subsequent
 993         //    creations can reuse this object.
 994     }
 995 
 996     class AttributeManager {
 997         Name attributeName = null;
 998         String attributeValue = null;
 999 
1000         public void setName(Name newName) throws SOAPException {
1001             clearAttribute();
1002             attributeName = newName;
1003             reconcileAttribute();
1004         }
1005         public void clearName() {
1006             clearAttribute();
1007             attributeName = null;
1008         }
1009         public void setValue(String value) throws SOAPException {
1010             attributeValue = value;
1011             reconcileAttribute();
1012         }
1013         public Name getName() {
1014             return attributeName;
1015         }
1016         public String getValue() {
1017             return attributeValue;
1018         }
1019 
1020         /** Note: to be used only in detachNode method */
1021         public void clearNameAndValue() {
1022             attributeName = null;
1023             attributeValue = null;
1024         }
1025 
1026         private void reconcileAttribute() throws SOAPException {
1027             if (attributeName != null) {
1028                 removeAttribute(attributeName);
1029                 if (attributeValue != null) {
1030                     addAttribute(attributeName, attributeValue);
1031                 }
1032             }
1033         }
1034         private void clearAttribute() {
1035             if (attributeName != null) {
1036                 removeAttribute(attributeName);
1037             }
1038         }
1039     }
1040 
1041     protected static org.w3c.dom.Attr getNamespaceAttrFrom(
1042         Element element,
1043         String prefix) {
1044         NamespaceContextIterator eachNamespace =
1045             new NamespaceContextIterator(element);
1046         while (eachNamespace.hasNext()) {
1047             org.w3c.dom.Attr namespaceDecl = eachNamespace.nextNamespaceAttr();
1048             String declaredPrefix =
1049                 NameImpl.getLocalNameFromTagName(namespaceDecl.getNodeName());
1050             if (declaredPrefix.equals(prefix)) {
1051                 return namespaceDecl;
1052             }
1053         }
1054         return null;
1055     }
1056 
1057     protected static Iterator getAllAttributesFrom(final Element element) {
1058         final NamedNodeMap attributes = element.getAttributes();
1059 
1060         return new Iterator() {
1061             int attributesLength = attributes.getLength();
1062             int attributeIndex = 0;
1063             String currentName;
1064 
1065             public boolean hasNext() {
1066                 return attributeIndex < attributesLength;
1067             }
1068 
1069             public Object next() {
1070                 if (!hasNext()) {
1071                     throw new NoSuchElementException();
1072                 }
1073                 Node current = attributes.item(attributeIndex++);
1074                 currentName = current.getNodeName();
1075 
1076                 String prefix = NameImpl.getPrefixFromTagName(currentName);
1077                 if (prefix.length() == 0) {
1078                     return NameImpl.createFromUnqualifiedName(currentName);
1079                 } else {
1080                     Name attributeName =
1081                         NameImpl.createFromQualifiedName(
1082                             currentName,
1083                             current.getNamespaceURI());
1084                     return attributeName;
1085                 }
1086             }
1087 
1088             public void remove() {
1089                 if (currentName == null) {
1090                     throw new IllegalStateException();
1091                 }
1092                 attributes.removeNamedItem(currentName);
1093             }
1094         };
1095     }
1096 
1097     protected static String getAttributeValueFrom(Element element, Name name) {
1098       return getAttributeValueFrom(
1099           element,
1100           name.getURI(),
1101           name.getLocalName(),
1102           name.getPrefix(),
1103           name.getQualifiedName());
1104     }
1105 
1106     private static String getAttributeValueFrom(
1107         Element element,
1108         String uri,
1109         String localName,
1110         String prefix,
1111         String qualifiedName) {
1112 
1113         String nonzeroLengthUri =
1114             (uri == null || uri.length() == 0) ? null : uri;
1115 
1116         boolean mustUseGetAttributeNodeNS =  (nonzeroLengthUri != null);
1117 
1118         if (mustUseGetAttributeNodeNS) {
1119 
1120             if (!element.hasAttributeNS(uri, localName)) {
1121                 return null;
1122             }
1123 
1124             String attrValue =
1125                 element.getAttributeNS(nonzeroLengthUri, localName);
1126 
1127             return attrValue;
1128         }
1129 
1130         Attr attribute = null;
1131         attribute = element.getAttributeNode(qualifiedName);
1132 
1133         return attribute == null ? null : attribute.getValue();
1134     }
1135 
1136     protected static Iterator getChildElementsFrom(final Element element) {
1137         return new Iterator() {
1138             Node next = element.getFirstChild();
1139             Node nextNext = null;
1140             Node last = null;
1141 
1142             public boolean hasNext() {
1143                 if (next != null) {
1144                     return true;
1145                 }
1146                 if (next == null && nextNext != null) {
1147                     next = nextNext;
1148                 }
1149 
1150                 return next != null;
1151             }
1152 
1153             public Object next() {
1154                 if (hasNext()) {
1155                     last = next;
1156                     next = null;
1157 
1158                     if ((element instanceof ElementImpl)
1159                         && (last instanceof Element)) {
1160                         last =
1161                             ((ElementImpl) element).convertToSoapElement(
1162                                 (Element) last);
1163                     }
1164 
1165                     nextNext = last.getNextSibling();
1166                     return last;
1167                 }
1168                 throw new NoSuchElementException();
1169             }
1170 
1171             public void remove() {
1172                 if (last == null) {
1173                     throw new IllegalStateException();
1174                 }
1175                 Node target = last;
1176                 last = null;
1177                 element.removeChild(target);
1178             }
1179         };
1180     }
1181 
1182     public static String getQualifiedName(QName name) {
1183         String prefix = name.getPrefix();
1184         String localName = name.getLocalPart();
1185         String qualifiedName = null;
1186 
1187             if (prefix != null && prefix.length() > 0) {
1188                 qualifiedName = prefix + ":" + localName;
1189             } else {
1190                 qualifiedName = localName;
1191             }
1192          return qualifiedName;
1193     }
1194 
1195     public static String getLocalPart(String qualifiedName) {
1196         if (qualifiedName == null) {
1197             // Log
1198             throw new IllegalArgumentException("Cannot get local name for a \"null\" qualified name");
1199         }
1200 
1201         int index = qualifiedName.indexOf(':');
1202         if (index < 0)
1203             return qualifiedName;
1204         else
1205             return qualifiedName.substring(index + 1);
1206     }
1207 
1208     public static String getPrefix(String qualifiedName) {
1209         if (qualifiedName == null) {
1210             // Log
1211             throw new IllegalArgumentException("Cannot get prefix for a  \"null\" qualified name");
1212         }
1213 
1214         int index = qualifiedName.indexOf(':');
1215         if (index < 0)
1216             return "";
1217         else
1218             return qualifiedName.substring(0, index);
1219     }
1220 
1221     protected boolean isNamespaceQualified(Name name) {
1222         return !"".equals(name.getURI());
1223     }
1224 
1225     protected boolean isNamespaceQualified(QName name) {
1226         return !"".equals(name.getNamespaceURI());
1227     }
1228 
1229     protected SOAPElement circumventBug5034339(SOAPElement element) {
1230 
1231         Name elementName = element.getElementName();
1232         if (!isNamespaceQualified(elementName)) {
1233             String prefix = elementName.getPrefix();
1234             String defaultNamespace = getNamespaceURI(prefix);
1235             if (defaultNamespace != null) {
1236                 Name newElementName =
1237                     NameImpl.create(
1238                         elementName.getLocalName(),
1239                         elementName.getPrefix(),
1240                         defaultNamespace);
1241                 SOAPElement newElement = createElement(newElementName);
1242                 replaceChild(newElement, element);
1243                 return newElement;
1244             }
1245         }
1246         return element;
1247     }
1248 
1249     //TODO: This is a temporary SAAJ workaround for optimizing XWS
1250     // should be removed once the corresponding JAXP bug is fixed
1251     // It appears the bug will be fixed in JAXP 1.4 (not by Appserver 9 timeframe)
1252     public void setAttributeNS(
1253         String namespaceURI,String qualifiedName, String value) {
1254         int index = qualifiedName.indexOf(':');
1255         String localName;
1256         if (index < 0)
1257             localName = qualifiedName;
1258         else
1259             localName = qualifiedName.substring(index + 1);
1260 
1261         // Workaround for bug 6467808 - This needs to be fixed in JAXP
1262 
1263         // Rolling back this fix, this is a wrong fix, infact its causing other regressions in JAXWS tck and
1264         // other tests, because of this change the namespace declarations on soapenv:Fault element are never
1265         // picked up. The fix for bug 6467808 should be in JAXP.
1266 //        if(elementQName.getLocalPart().equals("Fault") &&
1267 //                (SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE.equals(value) ||
1268 //                SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE.equals(value)))
1269 //            return;
1270 
1271         super.setAttributeNS(namespaceURI,qualifiedName,value);
1272         //String tmpLocalName = this.getLocalName();
1273         String tmpURI = this.getNamespaceURI();
1274         boolean isIDNS = false;
1275         if( tmpURI != null && (tmpURI.equals(DSIG_NS) || tmpURI.equals(XENC_NS))){
1276             isIDNS = true;
1277         }
1278         //No need to check for Signature/encryption element
1279         //just check for namespace.
1280         if(localName.equals("Id")){
1281             if(namespaceURI == null || namespaceURI.equals("")){
1282                 setIdAttribute(localName,true);
1283             }else if(isIDNS || WSU_NS.equals(namespaceURI)){
1284                 setIdAttributeNS(namespaceURI,localName,true);
1285             }
1286         }
1287 
1288     }
1289 
1290 }