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 
  26 package com.sun.xml.internal.messaging.saaj.soap;
  27 
  28 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  29 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeBodyPart;
  30 import com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl;
  31 import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl;
  32 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  33 import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
  34 import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
  35 import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection;
  36 import com.sun.xml.internal.messaging.saaj.util.JAXMStreamSource;
  37 import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants;
  38 import com.sun.xml.internal.messaging.saaj.util.MimeHeadersUtil;
  39 import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
  40 import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser;
  41 import org.w3c.dom.Attr;
  42 import org.w3c.dom.CDATASection;
  43 import org.w3c.dom.Comment;
  44 import org.w3c.dom.DOMConfiguration;
  45 import org.w3c.dom.DOMException;
  46 import org.w3c.dom.DOMImplementation;
  47 import org.w3c.dom.Document;
  48 import org.w3c.dom.DocumentFragment;
  49 import org.w3c.dom.DocumentType;
  50 import org.w3c.dom.Element;
  51 import org.w3c.dom.EntityReference;
  52 import org.w3c.dom.NamedNodeMap;
  53 import org.w3c.dom.NodeList;
  54 import org.w3c.dom.ProcessingInstruction;
  55 import org.w3c.dom.UserDataHandler;
  56 
  57 import javax.activation.DataHandler;
  58 import javax.activation.DataSource;
  59 import javax.xml.soap.MimeHeaders;
  60 import javax.xml.soap.SOAPElement;
  61 import javax.xml.soap.SOAPEnvelope;
  62 import javax.xml.soap.SOAPException;
  63 import javax.xml.soap.SOAPPart;
  64 import javax.xml.transform.Source;
  65 import javax.xml.transform.dom.DOMSource;
  66 import javax.xml.transform.sax.SAXSource;
  67 import javax.xml.transform.stream.StreamSource;
  68 import java.io.IOException;
  69 import java.io.InputStream;
  70 import java.io.InputStreamReader;
  71 import java.io.OutputStream;
  72 import java.io.PushbackReader;
  73 import java.io.Reader;
  74 import java.io.UnsupportedEncodingException;
  75 import java.util.Iterator;
  76 import java.util.logging.Level;
  77 import java.util.logging.Logger;
  78 import javax.xml.soap.MimeHeader;
  79 
  80 /**
  81  * SOAPPartImpl is the first attachment. This contains the XML/SOAP document.
  82  *
  83  * @author Anil Vijendran (anil@sun.com)
  84  */
  85 public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument {
  86     protected static final Logger log =
  87         Logger.getLogger(LogDomainConstants.SOAP_DOMAIN,
  88                          "com.sun.xml.internal.messaging.saaj.soap.LocalStrings");
  89 
  90     protected MimeHeaders headers;
  91     protected Envelope envelope;
  92     protected Source source;
  93     protected SOAPDocumentImpl document;
  94 
  95     //flag to indicate if a setContent happened.
  96     private boolean sourceWasSet = false;
  97 
  98     // Records whether the input source had an xml decl or not.
  99     protected boolean omitXmlDecl = true;
 100 
 101     // Records the charset encoding of the input stream source if provided.
 102     protected String sourceCharsetEncoding = null;
 103 
 104     /**
 105      * Reference to containing message (may be null)
 106      */
 107     protected MessageImpl message;
 108 
 109     static final boolean lazyContentLength;
 110     static {
 111             lazyContentLength = SAAJUtil.getSystemBoolean("saaj.lazy.contentlength");
 112     }
 113 
 114     protected SOAPPartImpl() {
 115         this(null);
 116     }
 117 
 118     protected SOAPPartImpl(MessageImpl message) {
 119         document = new SOAPDocumentImpl(this);
 120         headers = new MimeHeaders();
 121         this.message = message;
 122         headers.setHeader("Content-Type", getContentType());
 123     }
 124 
 125     protected abstract String getContentType();
 126     protected abstract Envelope createEnvelopeFromSource()
 127     throws SOAPException;
 128     protected abstract Envelope createEmptyEnvelope(String prefix)
 129     throws SOAPException;
 130     protected abstract SOAPPartImpl duplicateType();
 131 
 132     protected String getContentTypeString() {
 133         return getContentType();
 134     }
 135 
 136     public boolean isFastInfoset() {
 137         return (message != null) ? message.isFastInfoset() : false;
 138     }
 139 
 140     @Override
 141     public SOAPEnvelope getEnvelope() throws SOAPException {
 142 
 143         // If there is no SOAP envelope already created, then create
 144         // one from a source if one exists. If there is a newer source
 145         // then use that source.
 146 
 147         if (sourceWasSet)
 148               sourceWasSet = false;
 149 
 150         lookForEnvelope();
 151         if (envelope != null) {
 152             if (source != null) { // there's a newer source, use it
 153                 document.removeChild(envelope);
 154                 envelope = createEnvelopeFromSource();
 155             }
 156         } else if (source != null) {
 157             envelope = createEnvelopeFromSource();
 158         } else {
 159             envelope = createEmptyEnvelope(null);
 160             document.insertBefore(((EnvelopeImpl) envelope).getDomElement(), null);
 161         }
 162         return envelope;
 163     }
 164 
 165     protected void lookForEnvelope() throws SOAPException {
 166         Element envelopeChildElement = document.doGetDocumentElement();
 167         org.w3c.dom.Node soapEnvelope = document.findIfPresent(envelopeChildElement);
 168         if (soapEnvelope == null || soapEnvelope instanceof Envelope) {
 169             envelope = (EnvelopeImpl) soapEnvelope;
 170         } else if (document.find(envelopeChildElement) == null) {
 171             log.severe("SAAJ0512.soap.incorrect.factory.used");
 172             throw new SOAPExceptionImpl("Unable to create envelope: incorrect factory used during tree construction");
 173         } else {
 174             ElementImpl soapElement = (ElementImpl) document.find(envelopeChildElement);
 175             if (soapElement.getLocalName().equalsIgnoreCase("Envelope")) {
 176                 String prefix = soapElement.getPrefix();
 177                 String uri = (prefix == null) ? soapElement.getNamespaceURI() : soapElement.getNamespaceURI(prefix);
 178                 if(!uri.equals(NameImpl.SOAP11_NAMESPACE) && !uri.equals(NameImpl.SOAP12_NAMESPACE)) {
 179                     log.severe("SAAJ0513.soap.unknown.ns");
 180                     throw new SOAPVersionMismatchException("Unable to create envelope from given source because the namespace was not recognized");
 181                 }
 182             } else {
 183                 log.severe("SAAJ0514.soap.root.elem.not.named.envelope");
 184                 throw new SOAPExceptionImpl(
 185                     "Unable to create envelope from given source because the root element is not named \"Envelope\"");
 186             }
 187         }
 188     }
 189 
 190     @Override
 191     public void removeAllMimeHeaders() {
 192         headers.removeAllHeaders();
 193     }
 194 
 195     @Override
 196     public void removeMimeHeader(String header) {
 197         headers.removeHeader(header);
 198     }
 199 
 200     @Override
 201     public String[] getMimeHeader(String name) {
 202         return headers.getHeader(name);
 203     }
 204 
 205     @Override
 206     public void setMimeHeader(String name, String value) {
 207         headers.setHeader(name, value);
 208     }
 209 
 210     @Override
 211     public void addMimeHeader(String name, String value) {
 212         headers.addHeader(name, value);
 213     }
 214 
 215     @Override
 216     public Iterator<MimeHeader> getAllMimeHeaders() {
 217         return headers.getAllHeaders();
 218     }
 219 
 220     @Override
 221     public Iterator<MimeHeader> getMatchingMimeHeaders(String[] names) {
 222         return headers.getMatchingHeaders(names);
 223     }
 224 
 225     @Override
 226     public Iterator<MimeHeader> getNonMatchingMimeHeaders(String[] names) {
 227         return headers.getNonMatchingHeaders(names);
 228     }
 229 
 230     @Override
 231     public Source getContent() throws SOAPException {
 232         if (source != null) {
 233             InputStream bis = null;
 234             if (source instanceof JAXMStreamSource) {
 235                 StreamSource streamSource = (StreamSource)source;
 236                 bis = streamSource.getInputStream();
 237             } else if (FastInfosetReflection.isFastInfosetSource(source)) {
 238                 // FastInfosetSource inherits from SAXSource
 239                 SAXSource saxSource = (SAXSource)source;
 240                 bis = saxSource.getInputSource().getByteStream();
 241             }
 242 
 243             if (bis != null) {
 244                 try {
 245                     bis.reset();
 246                 } catch (IOException e) {
 247                     /* This exception will never be thrown.
 248                      *
 249                      * The setContent method will modify the source
 250                      * if StreamSource to JAXMStreamSource, that uses
 251                      * a ByteInputStream, and for a FastInfosetSource will
 252                      * replace the InputStream with a ByteInputStream.
 253                      */
 254                 }
 255             }
 256             return source;
 257         }
 258 
 259         return ((Envelope) getEnvelope()).getContent();
 260     }
 261 
 262     @Override
 263     public void setContent(Source source) throws SOAPException {
 264         try {
 265             if (source instanceof StreamSource) {
 266                 InputStream is = ((StreamSource) source).getInputStream();
 267                 Reader rdr = ((StreamSource) source).getReader();
 268 
 269                 if (is != null) {
 270                     this.source = new JAXMStreamSource(is);
 271                 } else if (rdr != null) {
 272                     this.source = new JAXMStreamSource(rdr);
 273                 } else {
 274                     log.severe("SAAJ0544.soap.no.valid.reader.for.src");
 275                     throw new SOAPExceptionImpl("Source does not have a valid Reader or InputStream");
 276                 }
 277             }
 278             else if (FastInfosetReflection.isFastInfosetSource(source)) {
 279                 // InputStream is = source.getInputStream()
 280                 InputStream is = FastInfosetReflection.FastInfosetSource_getInputStream(source);
 281 
 282                 /*
 283                  * Underlying stream must be ByteInputStream for getContentAsStream(). We pay the
 284                  * cost of copying the underlying bytes here to avoid multiple copies every time
 285                  * getBytes() is called on a ByteInputStream.
 286                  */
 287                 if (!(is instanceof ByteInputStream)) {
 288                     ByteOutputStream bout = null;
 289                     try {
 290                         bout = new ByteOutputStream();
 291                         bout.write(is);
 292 
 293                         // source.setInputStream(new ByteInputStream(...))
 294                         FastInfosetReflection.FastInfosetSource_setInputStream(
 295                                 source, bout.newInputStream());
 296                     } finally {
 297                         if (bout != null)
 298                             bout.close();
 299                     }
 300                 }
 301                 this.source = source;
 302             }
 303             else {
 304                 this.source = source;
 305             }
 306             sourceWasSet = true;
 307         }
 308         catch (Exception ex) {
 309             ex.printStackTrace();
 310 
 311             log.severe("SAAJ0545.soap.cannot.set.src.for.part");
 312             throw new SOAPExceptionImpl(
 313             "Error setting the source for SOAPPart: " + ex.getMessage());
 314         }
 315     }
 316 
 317     public InputStream getContentAsStream() throws IOException {
 318         if (source != null) {
 319             InputStream is = null;
 320 
 321             // Allow message to be transcode if so requested
 322             if (source instanceof StreamSource && !isFastInfoset()) {
 323                 is = ((StreamSource) source).getInputStream();
 324             }
 325             else if (FastInfosetReflection.isFastInfosetSource(source) &&
 326                 isFastInfoset())
 327             {
 328                 try {
 329                     // InputStream is = source.getInputStream()
 330                     is = FastInfosetReflection.FastInfosetSource_getInputStream(source);
 331                 }
 332                 catch (Exception e) {
 333                     throw new IOException(e.toString());
 334                 }
 335             }
 336 
 337             if (is != null) {
 338                 if (lazyContentLength) {
 339                     return is;
 340                 }
 341                 if (!(is instanceof ByteInputStream)) {
 342                     log.severe("SAAJ0546.soap.stream.incorrect.type");
 343                     throw new IOException("Internal error: stream not of the right type");
 344                 }
 345                 return (ByteInputStream) is;
 346             }
 347             // need to do something here for reader...
 348             // for now we'll see if we can fallback...
 349         }
 350 
 351         ByteOutputStream b = new ByteOutputStream();
 352 
 353         Envelope env = null;
 354 
 355         try {
 356             env = (Envelope) getEnvelope();
 357             env.output(b, isFastInfoset());
 358         }
 359         catch (SOAPException soapException) {
 360             log.severe("SAAJ0547.soap.cannot.externalize");
 361             throw new SOAPIOException(
 362             "SOAP exception while trying to externalize: ",
 363             soapException);
 364         }
 365 
 366         return b.newInputStream();
 367     }
 368 
 369     MimeBodyPart getMimePart() throws SOAPException {
 370         try {
 371             MimeBodyPart headerEnvelope = new MimeBodyPart();
 372 
 373             headerEnvelope.setDataHandler(getDataHandler());
 374             AttachmentPartImpl.copyMimeHeaders(headers, headerEnvelope);
 375 
 376             return headerEnvelope;
 377         } catch (SOAPException ex) {
 378             throw ex;
 379         } catch (Exception ex) {
 380             log.severe("SAAJ0548.soap.cannot.externalize.hdr");
 381             throw new SOAPExceptionImpl("Unable to externalize header", ex);
 382         }
 383     }
 384 
 385     MimeHeaders getMimeHeaders() {
 386         return headers;
 387     }
 388 
 389     DataHandler getDataHandler() {
 390         DataSource ds = new DataSource() {
 391             @Override
 392             public OutputStream getOutputStream() throws IOException {
 393                 throw new IOException("Illegal Operation");
 394             }
 395 
 396             @Override
 397             public String getContentType() {
 398                 return getContentTypeString();
 399             }
 400 
 401             @Override
 402             public String getName() {
 403                 return getContentId();
 404             }
 405 
 406             @Override
 407             public InputStream getInputStream() throws IOException {
 408                 return getContentAsStream();
 409             }
 410         };
 411         return new DataHandler(ds);
 412     }
 413 
 414     @Override
 415     public SOAPDocumentImpl getDocument() {
 416         handleNewSource();
 417         return document;
 418     }
 419 
 420     @Override
 421     public SOAPPartImpl getSOAPPart() {
 422         return this;
 423     }
 424 
 425     @Override
 426     public DocumentType getDoctype() {
 427         return document.getDoctype();
 428     }
 429 
 430     // Forward all of these calls to the document to ensure that they work the
 431     // same way whether they are called from here or directly from the document.
 432     // If the document needs any help from this SOAPPart then
 433     // Make it use a call-back as in doGetDocumentElement() below
 434     @Override
 435     public DOMImplementation getImplementation() {
 436         return document.getImplementation();
 437     }
 438 
 439     @Override
 440     public Element getDocumentElement() {
 441         // If there is no SOAP envelope already created, then create
 442         // one from a source if one exists. If there is a newer source
 443         // then use that source.
 444         try {
 445             getEnvelope();
 446         } catch (SOAPException e) {
 447         }
 448         return document.getDocumentElement();
 449     }
 450 
 451     protected void doGetDocumentElement() {
 452         handleNewSource();
 453         try {
 454             lookForEnvelope();
 455         } catch (SOAPException e) {
 456         }
 457     }
 458 
 459     @Override
 460     public Element createElement(String tagName) throws DOMException {
 461         return document.createElement(tagName);
 462     }
 463 
 464     @Override
 465     public DocumentFragment createDocumentFragment() {
 466         return document.createDocumentFragment();
 467     }
 468 
 469     @Override
 470     public org.w3c.dom.Text createTextNode(String data) {
 471         return document.createTextNode(data);
 472     }
 473 
 474     @Override
 475     public Comment createComment(String data) {
 476         return document.createComment(data);
 477     }
 478 
 479     @Override
 480     public CDATASection createCDATASection(String data) throws DOMException {
 481         return document.createCDATASection(data);
 482     }
 483 
 484     @Override
 485     public ProcessingInstruction createProcessingInstruction(
 486     String target,
 487     String data)
 488     throws DOMException {
 489         return document.createProcessingInstruction(target, data);
 490     }
 491 
 492     @Override
 493     public Attr createAttribute(String name) throws DOMException {
 494         return document.createAttribute(name);
 495     }
 496 
 497     @Override
 498     public EntityReference createEntityReference(String name)
 499     throws DOMException {
 500         return document.createEntityReference(name);
 501     }
 502 
 503     @Override
 504     public NodeList getElementsByTagName(String tagname) {
 505         handleNewSource();
 506         return document.getElementsByTagName(tagname);
 507     }
 508 
 509     @Override
 510     public org.w3c.dom.Node importNode(
 511         org.w3c.dom.Node importedNode,
 512         boolean deep)
 513         throws DOMException {
 514         handleNewSource();
 515         return document.importNode(importedNode, deep);
 516     }
 517 
 518     @Override
 519     public Element createElementNS(String namespaceURI, String qualifiedName)
 520     throws DOMException {
 521         return document.createElementNS(namespaceURI, qualifiedName);
 522     }
 523 
 524     @Override
 525     public Attr createAttributeNS(String namespaceURI, String qualifiedName)
 526     throws DOMException {
 527         return document.createAttributeNS(namespaceURI, qualifiedName);
 528     }
 529 
 530     @Override
 531     public NodeList getElementsByTagNameNS(
 532         String namespaceURI,
 533         String localName) {
 534         handleNewSource();
 535         return document.getElementsByTagNameNS(namespaceURI, localName);
 536     }
 537 
 538     @Override
 539     public Element getElementById(String elementId) {
 540         handleNewSource();
 541         return document.getElementById(elementId);
 542     }
 543     @Override
 544     public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild)
 545         throws DOMException {
 546         handleNewSource();
 547         return document.appendChild(newChild);
 548     }
 549 
 550     @Override
 551     public org.w3c.dom.Node cloneNode(boolean deep) {
 552         handleNewSource();
 553         return document.cloneNode(deep);
 554     }
 555 
 556     protected SOAPPartImpl doCloneNode() {
 557         handleNewSource();
 558         SOAPPartImpl newSoapPart = duplicateType();
 559 
 560         newSoapPart.headers = MimeHeadersUtil.copy(this.headers);
 561         newSoapPart.source = this.source;
 562         return newSoapPart;
 563     }
 564 
 565     @Override
 566     public NamedNodeMap getAttributes() {
 567         return document.getDomDocument().getAttributes();
 568     }
 569 
 570     @Override
 571     public NodeList getChildNodes() {
 572         handleNewSource();
 573         return document.getChildNodes();
 574     }
 575 
 576     @Override
 577     public org.w3c.dom.Node getFirstChild() {
 578         handleNewSource();
 579         return document.getFirstChild();
 580     }
 581 
 582     @Override
 583     public org.w3c.dom.Node getLastChild() {
 584         handleNewSource();
 585         return document.getLastChild();
 586     }
 587 
 588     @Override
 589     public String getLocalName() {
 590         return document.getDomDocument().getLocalName();
 591     }
 592 
 593     @Override
 594     public String getNamespaceURI() {
 595         return document.getDomDocument().getNamespaceURI();
 596     }
 597 
 598     @Override
 599     public org.w3c.dom.Node getNextSibling() {
 600         handleNewSource();
 601         return document.getNextSibling();
 602     }
 603 
 604     @Override
 605     public String getNodeName() {
 606         return document.getDomDocument().getNodeName();
 607     }
 608 
 609     @Override
 610     public short getNodeType() {
 611         return document.getDomDocument().getNodeType();
 612     }
 613 
 614     @Override
 615     public String getNodeValue() throws DOMException {
 616         return document.getNodeValue();
 617     }
 618 
 619     @Override
 620     public Document getOwnerDocument() {
 621         return document;
 622     }
 623 
 624     @Override
 625     public org.w3c.dom.Node getParentNode() {
 626         return document.getDomDocument().getParentNode();
 627     }
 628 
 629     @Override
 630     public String getPrefix() {
 631         return document.getDomDocument().getPrefix();
 632     }
 633 
 634     @Override
 635     public org.w3c.dom.Node getPreviousSibling() {
 636         return document.getDomDocument().getPreviousSibling();
 637     }
 638 
 639     @Override
 640     public boolean hasAttributes() {
 641         return document.getDomDocument().hasAttributes();
 642     }
 643 
 644     @Override
 645     public boolean hasChildNodes() {
 646         handleNewSource();
 647         return document.hasChildNodes();
 648     }
 649 
 650     @Override
 651     public org.w3c.dom.Node insertBefore(
 652         org.w3c.dom.Node arg0,
 653         org.w3c.dom.Node arg1)
 654         throws DOMException {
 655         handleNewSource();
 656         return document.insertBefore(arg0, arg1);
 657     }
 658 
 659     @Override
 660     public boolean isSupported(String arg0, String arg1) {
 661         return document.getDomDocument().isSupported(arg0, arg1);
 662     }
 663 
 664     @Override
 665     public void normalize() {
 666         handleNewSource();
 667         document.normalize();
 668     }
 669 
 670     @Override
 671     public org.w3c.dom.Node removeChild(org.w3c.dom.Node arg0)
 672         throws DOMException {
 673         handleNewSource();
 674         return document.removeChild(arg0);
 675     }
 676 
 677     @Override
 678     public org.w3c.dom.Node replaceChild(
 679         org.w3c.dom.Node arg0,
 680         org.w3c.dom.Node arg1)
 681         throws DOMException {
 682         handleNewSource();
 683         return document.replaceChild(arg0, arg1);
 684     }
 685 
 686     @Override
 687     public void setNodeValue(String arg0) throws DOMException {
 688         document.setNodeValue(arg0);
 689     }
 690 
 691     @Override
 692     public void setPrefix(String arg0) throws DOMException {
 693         document.setPrefix(arg0);
 694     }
 695 
 696     private void handleNewSource() {
 697         if (sourceWasSet) {
 698          // There is a newer source use that source.
 699          try {
 700              getEnvelope();
 701          } catch (SOAPException e) {
 702          }
 703       }
 704     }
 705 
 706     protected XMLDeclarationParser lookForXmlDecl() throws SOAPException {
 707         if ((source != null) && (source instanceof StreamSource)) {
 708 
 709             Reader reader = null;
 710 
 711             InputStream inputStream = ((StreamSource) source).getInputStream();
 712             if (inputStream != null) {
 713                 if (getSourceCharsetEncoding() == null) {
 714                     reader = new InputStreamReader(inputStream);
 715                 } else {
 716                     try {
 717                         reader =
 718                             new InputStreamReader(
 719                                 inputStream, getSourceCharsetEncoding());
 720                     } catch (UnsupportedEncodingException uee) {
 721                         log.log(
 722                             Level.SEVERE,
 723                             "SAAJ0551.soap.unsupported.encoding",
 724                             new Object[] {getSourceCharsetEncoding()});
 725                         throw new SOAPExceptionImpl(
 726                             "Unsupported encoding " + getSourceCharsetEncoding(),
 727                             uee);
 728                     }
 729                 }
 730             } else {
 731                 reader = ((StreamSource) source).getReader();
 732             }
 733             if (reader != null) {
 734                 PushbackReader pushbackReader =
 735                     new PushbackReader(reader, 4096); //some size to unread <?xml ....?>
 736                 XMLDeclarationParser ev =
 737                         new XMLDeclarationParser(pushbackReader);
 738                 try {
 739                     ev.parse();
 740                 } catch (Exception e) {
 741                     log.log(
 742                         Level.SEVERE,
 743                         "SAAJ0552.soap.xml.decl.parsing.failed");
 744                     throw new SOAPExceptionImpl(
 745                         "XML declaration parsing failed", e);
 746                 }
 747                 String xmlDecl = ev.getXmlDeclaration();
 748                 if ((xmlDecl != null) && (xmlDecl.length() > 0)) {
 749                     this.omitXmlDecl = false;
 750                 }
 751                 if (lazyContentLength) {
 752                     source = new StreamSource(pushbackReader);
 753                 }
 754                 return ev;
 755             }
 756         } else if ((source != null) && (source instanceof DOMSource)) {
 757            //TODO: A Domsource maynot contain XMLDecl ?.
 758         }
 759         return null;
 760     }
 761 
 762     public void setSourceCharsetEncoding(String charset) {
 763         this.sourceCharsetEncoding = charset;
 764     }
 765 
 766     @Override
 767     public org.w3c.dom.Node renameNode(org.w3c.dom.Node n, String namespaceURI, String qualifiedName)
 768         throws DOMException {
 769         handleNewSource();
 770         return document.renameNode(n, namespaceURI, qualifiedName);
 771     }
 772 
 773     @Override
 774     public void normalizeDocument() {
 775         document.normalizeDocument();
 776     }
 777 
 778     @Override
 779     public DOMConfiguration getDomConfig() {
 780         return document.getDomDocument().getDomConfig();
 781     }
 782 
 783     @Override
 784     public org.w3c.dom.Node adoptNode(org.w3c.dom.Node source) throws DOMException {
 785         handleNewSource();
 786         return document.adoptNode(source);
 787     }
 788 
 789     @Override
 790     public void setDocumentURI(String documentURI) {
 791         document.setDocumentURI(documentURI);
 792     }
 793 
 794     @Override
 795     public String getDocumentURI() {
 796         return document.getDomDocument().getDocumentURI();
 797     }
 798 
 799     @Override
 800     public void  setStrictErrorChecking(boolean strictErrorChecking) {
 801         document.setStrictErrorChecking(strictErrorChecking);
 802     }
 803 
 804     @Override
 805     public String getInputEncoding() {
 806         return document.getDomDocument().getInputEncoding();
 807     }
 808 
 809     @Override
 810     public String getXmlEncoding() {
 811         return document.getDomDocument().getXmlEncoding();
 812     }
 813 
 814     @Override
 815     public boolean getXmlStandalone() {
 816         return document.getDomDocument().getXmlStandalone();
 817     }
 818 
 819     @Override
 820     public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
 821         document.setXmlStandalone(xmlStandalone);
 822     }
 823 
 824     @Override
 825     public String getXmlVersion() {
 826         return document.getDomDocument().getXmlVersion();
 827     }
 828 
 829     @Override
 830     public void setXmlVersion(String xmlVersion) throws DOMException {
 831         document.setXmlVersion(xmlVersion);
 832     }
 833 
 834     @Override
 835     public boolean  getStrictErrorChecking() {
 836         return document.getDomDocument().getStrictErrorChecking();
 837     }
 838 
 839     // DOM L3 methods from org.w3c.dom.Node
 840     @Override
 841     public String getBaseURI() {
 842         return document.getDomDocument().getBaseURI();
 843     }
 844 
 845     @Override
 846     public short compareDocumentPosition(org.w3c.dom.Node other)
 847                               throws DOMException {
 848         return document.compareDocumentPosition(other);
 849     }
 850 
 851     @Override
 852     public String getTextContent()
 853                       throws DOMException {
 854         return document.getTextContent();
 855     }
 856 
 857     @Override
 858     public void setTextContent(String textContent) throws DOMException {
 859          document.setTextContent(textContent);
 860     }
 861 
 862     @Override
 863     public boolean isSameNode(org.w3c.dom.Node other) {
 864         return document.isSameNode(other);
 865     }
 866 
 867     @Override
 868     public String lookupPrefix(String namespaceURI) {
 869         return document.getDomDocument().lookupPrefix(namespaceURI);
 870     }
 871 
 872     @Override
 873     public boolean isDefaultNamespace(String namespaceURI) {
 874         return document.isDefaultNamespace(namespaceURI);
 875     }
 876 
 877     @Override
 878     public String lookupNamespaceURI(String prefix) {
 879         return document.lookupNamespaceURI(prefix);
 880     }
 881 
 882     @Override
 883     public boolean isEqualNode(org.w3c.dom.Node arg) {
 884         return document.getDomDocument().isEqualNode(arg);
 885     }
 886 
 887     @Override
 888     public Object getFeature(String feature,
 889                   String version) {
 890         return  document.getFeature(feature,version);
 891     }
 892 
 893     @Override
 894     public Object setUserData(String key,
 895                    Object data,
 896                   UserDataHandler handler) {
 897         return document.setUserData(key, data, handler);
 898     }
 899 
 900     @Override
 901     public Object getUserData(String key) {
 902         return document.getDomDocument().getUserData(key);
 903     }
 904 
 905     @Override
 906     public void recycleNode() {
 907         // Nothing seems to be required to be done here
 908     }
 909 
 910     @Override
 911     public String getValue() {
 912         return null;
 913     }
 914 
 915     @Override
 916     public void setValue(String value) {
 917         log.severe("SAAJ0571.soappart.setValue.not.defined");
 918         throw new IllegalStateException("Setting value of a soap part is not defined");
 919     }
 920 
 921     @Override
 922     public void setParentElement(SOAPElement parent) throws SOAPException {
 923         log.severe("SAAJ0570.soappart.parent.element.not.defined");
 924         throw new SOAPExceptionImpl("The parent element of a soap part is not defined");
 925     }
 926 
 927     @Override
 928     public SOAPElement getParentElement() {
 929         return null;
 930     }
 931 
 932     @Override
 933     public void detachNode() {
 934         // Nothing seems to be required to be done here
 935     }
 936 
 937     public String getSourceCharsetEncoding() {
 938         return sourceCharsetEncoding;
 939     }
 940 
 941     public abstract String getSOAPNamespace();
 942 }