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 /**
  27 *
  28 * @author SAAJ RI Development Team
  29 */
  30 package com.sun.xml.internal.messaging.saaj.soap;
  31 
  32 import com.sun.xml.internal.messaging.saaj.soap.impl.CDATAImpl;
  33 import com.sun.xml.internal.messaging.saaj.soap.impl.ElementFactory;
  34 import com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl;
  35 import com.sun.xml.internal.messaging.saaj.soap.impl.NamedNodeMapImpl;
  36 import com.sun.xml.internal.messaging.saaj.soap.impl.NodeListImpl;
  37 import com.sun.xml.internal.messaging.saaj.soap.impl.SOAPCommentImpl;
  38 import com.sun.xml.internal.messaging.saaj.soap.impl.SOAPTextImpl;
  39 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  40 import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants;
  41 import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
  42 import org.w3c.dom.Attr;
  43 import org.w3c.dom.CDATASection;
  44 import org.w3c.dom.CharacterData;
  45 import org.w3c.dom.Comment;
  46 import org.w3c.dom.DOMConfiguration;
  47 import org.w3c.dom.DOMException;
  48 import org.w3c.dom.DOMImplementation;
  49 import org.w3c.dom.Document;
  50 import org.w3c.dom.DocumentFragment;
  51 import org.w3c.dom.DocumentType;
  52 import org.w3c.dom.Element;
  53 import org.w3c.dom.EntityReference;
  54 import org.w3c.dom.NamedNodeMap;
  55 import org.w3c.dom.Node;
  56 import org.w3c.dom.NodeList;
  57 import org.w3c.dom.ProcessingInstruction;
  58 import org.w3c.dom.Text;
  59 import org.w3c.dom.UserDataHandler;
  60 
  61 import javax.xml.parsers.DocumentBuilder;
  62 import javax.xml.parsers.DocumentBuilderFactory;
  63 import javax.xml.parsers.ParserConfigurationException;
  64 import javax.xml.soap.SOAPElement;
  65 import javax.xml.soap.SOAPException;
  66 import java.lang.reflect.Constructor;
  67 import java.text.MessageFormat;
  68 import java.util.logging.Logger;
  69 
  70 public class SOAPDocumentImpl implements SOAPDocument, javax.xml.soap.Node, Document {
  71 
  72     public static final String SAAJ_NODE = "javax.xml.soap.Node";
  73 
  74     private static final String XMLNS = "xmlns".intern();
  75     protected static final Logger log =
  76         Logger.getLogger(LogDomainConstants.SOAP_DOMAIN,
  77                          "com.sun.xml.internal.messaging.saaj.soap.LocalStrings");
  78 
  79     SOAPPartImpl enclosingSOAPPart;
  80 
  81     private Document document;
  82 
  83     public SOAPDocumentImpl(SOAPPartImpl enclosingDocument) {
  84         document = createDocument();
  85         this.enclosingSOAPPart = enclosingDocument;
  86         register(this);
  87     }
  88 
  89     private Document createDocument() {
  90         DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl", SAAJUtil.getSystemClassLoader());
  91         try {
  92             final DocumentBuilder documentBuilder = docFactory.newDocumentBuilder();
  93             return documentBuilder.newDocument();
  94         } catch (ParserConfigurationException e) {
  95             throw new RuntimeException("Error creating xml document", e);
  96         }
  97     }
  98 
  99     //    public SOAPDocumentImpl(boolean grammarAccess) {
 100     //        super(grammarAccess);
 101     //    }
 102     //
 103     //    public SOAPDocumentImpl(DocumentType doctype) {
 104     //        super(doctype);
 105     //    }
 106     //
 107     //    public SOAPDocumentImpl(DocumentType doctype, boolean grammarAccess) {
 108     //        super(doctype, grammarAccess);
 109     //    }
 110 
 111     @Override
 112     public SOAPPartImpl getSOAPPart() {
 113         if (enclosingSOAPPart == null) {
 114             log.severe("SAAJ0541.soap.fragment.not.bound.to.part");
 115             throw new RuntimeException("Could not complete operation. Fragment not bound to SOAP part.");
 116         }
 117         return enclosingSOAPPart;
 118     }
 119 
 120     @Override
 121     public SOAPDocumentImpl getDocument() {
 122         return this;
 123     }
 124 
 125     @Override
 126     public DocumentType getDoctype() {
 127         // SOAP means no DTD, No DTD means no doctype (SOAP 1.2 only?)
 128         return null;
 129     }
 130 
 131     @Override
 132     public DOMImplementation getImplementation() {
 133         return document.getImplementation();
 134     }
 135 
 136     @Override
 137     public Element getDocumentElement() {
 138         // This had better be an Envelope!
 139         getSOAPPart().doGetDocumentElement();
 140         return doGetDocumentElement();
 141     }
 142 
 143     protected Element doGetDocumentElement() {
 144         return document.getDocumentElement();
 145     }
 146 
 147     @Override
 148     public Element createElement(String tagName) throws DOMException {
 149         return ElementFactory.createElement(
 150             this,
 151             NameImpl.getLocalNameFromTagName(tagName),
 152             NameImpl.getPrefixFromTagName(tagName),
 153             null);
 154     }
 155 
 156     @Override
 157     public DocumentFragment createDocumentFragment() {
 158         return new SOAPDocumentFragment(this);
 159     }
 160 
 161     @Override
 162     public org.w3c.dom.Text createTextNode(String data) {
 163         return new SOAPTextImpl(this, data);
 164     }
 165 
 166     @Override
 167     public Comment createComment(String data) {
 168         return new SOAPCommentImpl(this, data);
 169     }
 170 
 171     @Override
 172     public CDATASection createCDATASection(String data) throws DOMException {
 173         return new CDATAImpl(this, data);
 174     }
 175 
 176     @Override
 177     public ProcessingInstruction createProcessingInstruction(
 178         String target,
 179         String data)
 180         throws DOMException {
 181         log.severe("SAAJ0542.soap.proc.instructions.not.allowed.in.docs");
 182         throw new UnsupportedOperationException("Processing Instructions are not allowed in SOAP documents");
 183     }
 184 
 185     @Override
 186     public Attr createAttribute(String name) throws DOMException {
 187         boolean isQualifiedName = (name.indexOf(":") > 0);
 188         if (isQualifiedName) {
 189             String nsUri = null;
 190             String prefix = name.substring(0, name.indexOf(":"));
 191             //cannot do anything to resolve the URI if prefix is not
 192             //XMLNS.
 193             if (XMLNS.equals(prefix)) {
 194                 nsUri = ElementImpl.XMLNS_URI;
 195                 return createAttributeNS(nsUri, name);
 196             }
 197         }
 198 
 199         return document.createAttribute(name);
 200     }
 201 
 202     @Override
 203     public EntityReference createEntityReference(String name)
 204         throws DOMException {
 205             log.severe("SAAJ0543.soap.entity.refs.not.allowed.in.docs");
 206             throw new UnsupportedOperationException("Entity References are not allowed in SOAP documents");
 207     }
 208 
 209     @Override
 210     public NodeList getElementsByTagName(String tagname) {
 211         return new NodeListImpl(this, document.getElementsByTagName(tagname));
 212     }
 213 
 214     @Override
 215     public org.w3c.dom.Node importNode(Node importedNode, boolean deep)
 216         throws DOMException {
 217         Node domNode = getDomNode(importedNode);
 218         final Node newNode = document.importNode(domNode, deep);
 219 
 220         if (importedNode instanceof javax.xml.soap.Node) {
 221             Node newSoapNode = createSoapNode(importedNode.getClass(), newNode);
 222             newNode.setUserData(SAAJ_NODE, newSoapNode, null);
 223             if (deep && newSoapNode.hasChildNodes()) {
 224                 NodeList childNodes = newSoapNode.getChildNodes();
 225                 for (int i = 0; i < childNodes.getLength(); i++) {
 226                     registerChildNodes(childNodes.item(i), deep);
 227                 }
 228             }
 229             return newSoapNode;
 230         }
 231 
 232         registerChildNodes(newNode, deep);
 233         return findIfPresent(newNode);
 234     }
 235 
 236     /**
 237      * If the parentNode is not registered to domToSoap, create soap wapper for parentNode and register it to domToSoap
 238      * If deep = true, also register all children transitively of parentNode to domToSoap map.
 239      * @param parentNode node to wrap
 240      * @param deep wrap child nodes transitively
 241      */
 242     public void registerChildNodes(Node parentNode, boolean deep) {
 243         if (parentNode.getUserData(SAAJ_NODE) == null) {
 244             if (parentNode instanceof Element) {
 245                 ElementFactory.createElement(this, (Element) parentNode);
 246             } else if (parentNode instanceof CharacterData) {
 247                 switch (parentNode.getNodeType()) {
 248                     case CDATA_SECTION_NODE:
 249                         new CDATAImpl(this, (CharacterData) parentNode);
 250                         break;
 251                     case COMMENT_NODE:
 252                         new SOAPCommentImpl(this, (CharacterData) parentNode);
 253                         break;
 254                     case TEXT_NODE:
 255                         new SOAPTextImpl(this, (CharacterData) parentNode);
 256                         break;
 257                 }
 258             } else if (parentNode instanceof DocumentFragment) {
 259                 new SOAPDocumentFragment(this, (DocumentFragment) parentNode);
 260             }
 261         }
 262         if (deep) {
 263             NodeList nodeList = parentNode.getChildNodes();
 264             for (int i = 0; i < nodeList.getLength(); i++) {
 265                 Node nextChild = nodeList.item(i);
 266                 registerChildNodes(nextChild, true);
 267             }
 268         }
 269     }
 270 
 271     @Override
 272     public Element createElementNS(String namespaceURI, String qualifiedName)
 273         throws DOMException {
 274         return ElementFactory.createElement(
 275             this,
 276             NameImpl.getLocalNameFromTagName(qualifiedName),
 277             NameImpl.getPrefixFromTagName(qualifiedName),
 278             namespaceURI);
 279     }
 280 
 281     @Override
 282     public Attr createAttributeNS(String namespaceURI, String qualifiedName)
 283         throws DOMException {
 284         return document.createAttributeNS(namespaceURI, qualifiedName);
 285     }
 286 
 287     @Override
 288     public NodeList getElementsByTagNameNS(
 289         String namespaceURI,
 290         String localName) {
 291         return new NodeListImpl(this, document.getElementsByTagNameNS(namespaceURI, localName));
 292     }
 293 
 294     @Override
 295     public Element getElementById(String elementId) {
 296         return (Element) findIfPresent(document.getElementById(elementId));
 297     }
 298 
 299     @Override
 300     public String getInputEncoding() {
 301         return document.getInputEncoding();
 302     }
 303 
 304     @Override
 305     public String getXmlEncoding() {
 306         return document.getXmlEncoding();
 307     }
 308 
 309     @Override
 310     public boolean getXmlStandalone() {
 311         return document.getXmlStandalone();
 312     }
 313 
 314     @Override
 315     public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
 316         document.setXmlStandalone(xmlStandalone);
 317     }
 318 
 319     @Override
 320     public String getXmlVersion() {
 321         return document.getXmlVersion();
 322     }
 323 
 324     @Override
 325     public void setXmlVersion(String xmlVersion) throws DOMException {
 326         document.setXmlVersion(xmlVersion);
 327     }
 328 
 329     @Override
 330     public boolean getStrictErrorChecking() {
 331         return document.getStrictErrorChecking();
 332     }
 333 
 334     @Override
 335     public void setStrictErrorChecking(boolean strictErrorChecking) {
 336         document.setStrictErrorChecking(strictErrorChecking);
 337     }
 338 
 339     @Override
 340     public String getDocumentURI() {
 341         return document.getDocumentURI();
 342     }
 343 
 344     @Override
 345     public void setDocumentURI(String documentURI) {
 346         document.setDocumentURI(documentURI);
 347     }
 348 
 349     @Override
 350     public Node adoptNode(Node source) throws DOMException {
 351         return document.adoptNode(source);
 352     }
 353 
 354     @Override
 355     public DOMConfiguration getDomConfig() {
 356         return document.getDomConfig();
 357     }
 358 
 359     @Override
 360     public void normalizeDocument() {
 361         document.normalizeDocument();
 362     }
 363 
 364     @Override
 365     public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException {
 366         return findIfPresent(document.renameNode(n, namespaceURI, qualifiedName));
 367     }
 368 
 369     @Override
 370     public String getNodeName() {
 371         return document.getNodeName();
 372     }
 373 
 374     @Override
 375     public String getNodeValue() throws DOMException {
 376         return document.getNodeValue();
 377     }
 378 
 379     @Override
 380     public void setNodeValue(String nodeValue) throws DOMException {
 381         document.setNodeValue(nodeValue);
 382     }
 383 
 384     @Override
 385     public short getNodeType() {
 386         return document.getNodeType();
 387     }
 388 
 389     @Override
 390     public Node getParentNode() {
 391         return findIfPresent(document.getParentNode());
 392     }
 393 
 394     @Override
 395     public NodeList getChildNodes() {
 396         return new NodeListImpl(this, document.getChildNodes());
 397     }
 398 
 399     @Override
 400     public Node getFirstChild() {
 401         return findIfPresent(document.getFirstChild());
 402     }
 403 
 404     @Override
 405     public Node getLastChild() {
 406         return findIfPresent(document.getLastChild());
 407     }
 408 
 409     @Override
 410     public Node getPreviousSibling() {
 411         return findIfPresent(document.getPreviousSibling());
 412     }
 413 
 414     @Override
 415     public Node getNextSibling() {
 416         return findIfPresent(document.getNextSibling());
 417     }
 418 
 419     @Override
 420     public NamedNodeMap getAttributes() {
 421         NamedNodeMap attributes = document.getAttributes();
 422         if (attributes == null) {
 423             return null;
 424         }
 425         return new NamedNodeMapImpl(attributes, this);
 426     }
 427 
 428     @Override
 429     public Document getOwnerDocument() {
 430         return document.getOwnerDocument();
 431     }
 432 
 433     @Override
 434     public Node insertBefore(Node newChild, Node refChild) throws DOMException {
 435         return document.insertBefore(getDomNode(newChild), getDomNode(refChild));
 436     }
 437 
 438     @Override
 439     public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
 440         return document.replaceChild(getDomNode(newChild), getDomNode(oldChild));
 441     }
 442 
 443     @Override
 444     public Node removeChild(Node oldChild) throws DOMException {
 445         return document.removeChild(getDomNode(oldChild));
 446     }
 447 
 448     @Override
 449     public Node appendChild(Node newChild) throws DOMException {
 450         return document.appendChild(getDomNode(newChild));
 451     }
 452 
 453     @Override
 454     public boolean hasChildNodes() {
 455         return document.hasChildNodes();
 456     }
 457 
 458     @Override
 459     public Node cloneNode(boolean deep) {
 460         Node node = document.cloneNode(deep);
 461         registerChildNodes(node, deep);
 462         return findIfPresent(node);
 463     }
 464 
 465     @Override
 466     public void normalize() {
 467         document.normalize();
 468     }
 469 
 470     @Override
 471     public boolean isSupported(String feature, String version) {
 472         return document.isSupported(feature, version);
 473     }
 474 
 475     @Override
 476     public String getNamespaceURI() {
 477         return document.getNamespaceURI();
 478     }
 479 
 480     @Override
 481     public String getPrefix() {
 482         return document.getPrefix();
 483     }
 484 
 485     @Override
 486     public void setPrefix(String prefix) throws DOMException {
 487         document.setPrefix(prefix);
 488     }
 489 
 490     @Override
 491     public String getLocalName() {
 492         return document.getLocalName();
 493     }
 494 
 495     @Override
 496     public boolean hasAttributes() {
 497         return document.hasAttributes();
 498     }
 499 
 500     @Override
 501     public String getBaseURI() {
 502         return document.getBaseURI();
 503     }
 504 
 505     @Override
 506     public short compareDocumentPosition(Node other) throws DOMException {
 507         return document.compareDocumentPosition(getDomNode(other));
 508     }
 509 
 510     @Override
 511     public String getTextContent() throws DOMException {
 512         return document.getTextContent();
 513     }
 514 
 515     @Override
 516     public void setTextContent(String textContent) throws DOMException {
 517         document.setTextContent(textContent);
 518     }
 519 
 520     @Override
 521     public boolean isSameNode(Node other) {
 522         return document.isSameNode(getDomNode(other));
 523     }
 524 
 525     @Override
 526     public String lookupPrefix(String namespaceURI) {
 527         return document.lookupPrefix(namespaceURI);
 528     }
 529 
 530     @Override
 531     public boolean isDefaultNamespace(String namespaceURI) {
 532         return document.isDefaultNamespace(namespaceURI);
 533     }
 534 
 535     @Override
 536     public String lookupNamespaceURI(String prefix) {
 537         return document.lookupNamespaceURI(prefix);
 538     }
 539 
 540     @Override
 541     public boolean isEqualNode(Node arg) {
 542         return document.isEqualNode(getDomNode(arg));
 543     }
 544 
 545     @Override
 546     public Object getFeature(String feature, String version) {
 547         return document.getFeature(feature, version);
 548     }
 549 
 550     @Override
 551     public Object setUserData(String key, Object data, UserDataHandler handler) {
 552         return document.setUserData(key, data, handler);
 553     }
 554 
 555     @Override
 556     public Object getUserData(String key) {
 557         return document.getUserData(key);
 558     }
 559 
 560     public Document getDomDocument() {
 561         return document;
 562     }
 563 
 564     /**
 565      * Insert a mapping information for {@link org.w3c.dom.Node} - {@link javax.xml.soap.Node}.
 566      *
 567      * In SAAJ, elements in DOM are expected to be interfaces of SAAJ, on the other hand in JDKs Xerces,
 568      * they are casted to internal impl classes. After removal of SAAJ dependency
 569      * to JDKs internal classes elements in DOM can never be both of them.
 570      *
 571      * @param node SAAJ wrapper node for w3c DOM node
 572      */
 573     public void register(javax.xml.soap.Node node) {
 574         final Node domElement = getDomNode(node);
 575         if (domElement.getUserData(SAAJ_NODE) != null) {
 576             throw new IllegalStateException("Element " + domElement.getNodeName()
 577                     + " is already registered");
 578         }
 579         domElement.setUserData(SAAJ_NODE, node, null);
 580     }
 581 
 582     /**
 583      * Find a soap wrapper for w3c dom node.
 584      *
 585      * @param node w3c dom node nullable
 586      * @return soap wrapper for w3c dom node
 587      *
 588      * @throws
 589      */
 590     public javax.xml.soap.Node find(Node node) {
 591         return find(node, true);
 592     }
 593 
 594     private javax.xml.soap.Node find(Node node, boolean required) {
 595         if (node == null) {
 596             return null;
 597         }
 598         if (node instanceof javax.xml.soap.Node) {
 599             return (javax.xml.soap.Node) node;
 600         }
 601         final javax.xml.soap.Node found = (javax.xml.soap.Node) node.getUserData(SAAJ_NODE);
 602         if (found == null && required) {
 603             throw new IllegalArgumentException(MessageFormat.format("Cannot find SOAP wrapper for element {0}", node));
 604         }
 605         return found;
 606     }
 607 
 608     /**
 609      * If corresponding soap wrapper exists for w3c dom node it is returned,
 610      * if not passed dom element is returned.
 611      *
 612      * @param node w3c dom node
 613      * @return soap wrapper or passed w3c dom node if not found
 614      */
 615     public Node findIfPresent(Node node) {
 616         final javax.xml.soap.Node found = find(node, false);
 617         return found != null ? found : node;
 618     }
 619 
 620     /**
 621      * Extracts w3c dom node from corresponding soap wrapper.
 622      *
 623      * @param node soap or dom nullable
 624      * @return dom node
 625      */
 626     public Node getDomNode(Node node) {
 627         if (node instanceof SOAPDocumentImpl) {
 628             return ((SOAPDocumentImpl)node).getDomElement();
 629         } else if (node instanceof ElementImpl) {
 630             return ((ElementImpl) node).getDomElement();
 631         } else if (node instanceof SOAPTextImpl) {
 632             return ((SOAPTextImpl)node).getDomElement();
 633         } else if (node instanceof SOAPCommentImpl) {
 634             return ((SOAPCommentImpl)node).getDomElement();
 635         } else if (node instanceof CDATAImpl) {
 636             return ((CDATAImpl) node).getDomElement();
 637         } else if (node instanceof SOAPDocumentFragment) {
 638             return ((SOAPDocumentFragment)node).getDomNode();
 639         }
 640         return node;
 641     }
 642 
 643 
 644     private Node createSoapNode(Class nodeType, Node node) {
 645         if (SOAPTextImpl.class.isAssignableFrom(nodeType)) {
 646             return new SOAPTextImpl(this, (Text) node);
 647         } else if (SOAPCommentImpl.class.isAssignableFrom(nodeType)) {
 648             return new SOAPCommentImpl(this, (Comment) node);
 649         } else if (CDATAImpl.class.isAssignableFrom(nodeType)) {
 650             return new CDATAImpl(this, (CDATASection) node);
 651         } else if (SOAPDocumentFragment.class.isAssignableFrom(nodeType)) {
 652             return new SOAPDocumentFragment(this, (DocumentFragment) node);
 653         }
 654         try {
 655             Constructor<Node> constructor = nodeType.getConstructor(SOAPDocumentImpl.class, Element.class);
 656             return constructor.newInstance(this, node);
 657         } catch (Exception e) {
 658             throw new IllegalStateException(e);
 659         }
 660     }
 661 
 662 
 663     public Document getDomElement() {
 664         return document;
 665     }
 666 
 667     @Override
 668     public String getValue() {
 669         throw new UnsupportedOperationException();
 670     }
 671 
 672     @Override
 673     public void setValue(String value) {
 674         throw new UnsupportedOperationException();
 675     }
 676 
 677     @Override
 678     public void setParentElement(SOAPElement parent) throws SOAPException {
 679         throw new UnsupportedOperationException();
 680     }
 681 
 682     @Override
 683     public SOAPElement getParentElement() {
 684         throw new UnsupportedOperationException();
 685     }
 686 
 687     @Override
 688     public void detachNode() {
 689         throw new UnsupportedOperationException();
 690     }
 691 
 692     @Override
 693     public void recycleNode() {
 694         throw new UnsupportedOperationException();
 695     }
 696 }