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 && importedNode.hasChildNodes()) { 224 NodeList childNodes = importedNode.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 //If the parentNode is not registered to domToSoap, create soap wapper for parentNode and register it to domToSoap 237 //If deep = true, also register all children of parentNode to domToSoap map. 238 public void registerChildNodes(Node parentNode, boolean deep) { 239 if (parentNode.getUserData(SAAJ_NODE) == null) { 240 if (parentNode instanceof Element) { 241 ElementFactory.createElement(this, (Element) parentNode); 242 } else if (parentNode instanceof CharacterData) { 243 switch (parentNode.getNodeType()) { 244 case CDATA_SECTION_NODE: 245 new CDATAImpl(this, (CharacterData) parentNode); 246 break; 247 case COMMENT_NODE: 248 new SOAPCommentImpl(this, (CharacterData) parentNode); 249 break; 250 case TEXT_NODE: 251 new SOAPTextImpl(this, (CharacterData) parentNode); 252 break; 253 } 254 } 255 } 256 if (deep) { 257 NodeList nodeList = parentNode.getChildNodes(); 258 for (int i = 0; i < nodeList.getLength(); i++) { 259 Node nextChild = nodeList.item(i); 260 registerChildNodes(nextChild, true); 261 } 262 } 263 } 264 265 @Override 266 public Element createElementNS(String namespaceURI, String qualifiedName) 267 throws DOMException { 268 return ElementFactory.createElement( 269 this, 270 NameImpl.getLocalNameFromTagName(qualifiedName), 271 NameImpl.getPrefixFromTagName(qualifiedName), 272 namespaceURI); 273 } 274 275 @Override 276 public Attr createAttributeNS(String namespaceURI, String qualifiedName) 277 throws DOMException { 278 return document.createAttributeNS(namespaceURI, qualifiedName); 279 } 280 281 @Override 282 public NodeList getElementsByTagNameNS( 283 String namespaceURI, 284 String localName) { 285 return new NodeListImpl(this, document.getElementsByTagNameNS(namespaceURI, localName)); 286 } 287 288 @Override 289 public Element getElementById(String elementId) { 290 return (Element) findIfPresent(document.getElementById(elementId)); 291 } 292 293 @Override 294 public String getInputEncoding() { 295 return document.getInputEncoding(); 296 } 297 298 @Override 299 public String getXmlEncoding() { 300 return document.getXmlEncoding(); 301 } 302 303 @Override 304 public boolean getXmlStandalone() { 305 return document.getXmlStandalone(); 306 } 307 308 @Override 309 public void setXmlStandalone(boolean xmlStandalone) throws DOMException { 310 document.setXmlStandalone(xmlStandalone); 311 } 312 313 @Override 314 public String getXmlVersion() { 315 return document.getXmlVersion(); 316 } 317 318 @Override 319 public void setXmlVersion(String xmlVersion) throws DOMException { 320 document.setXmlVersion(xmlVersion); 321 } 322 323 @Override 324 public boolean getStrictErrorChecking() { 325 return document.getStrictErrorChecking(); 326 } 327 328 @Override 329 public void setStrictErrorChecking(boolean strictErrorChecking) { 330 document.setStrictErrorChecking(strictErrorChecking); 331 } 332 333 @Override 334 public String getDocumentURI() { 335 return document.getDocumentURI(); 336 } 337 338 @Override 339 public void setDocumentURI(String documentURI) { 340 document.setDocumentURI(documentURI); 341 } 342 343 @Override 344 public Node adoptNode(Node source) throws DOMException { 345 return document.adoptNode(source); 346 } 347 348 @Override 349 public DOMConfiguration getDomConfig() { 350 return document.getDomConfig(); 351 } 352 353 @Override 354 public void normalizeDocument() { 355 document.normalizeDocument(); 356 } 357 358 @Override 359 public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException { 360 return findIfPresent(document.renameNode(n, namespaceURI, qualifiedName)); 361 } 362 363 @Override 364 public String getNodeName() { 365 return document.getNodeName(); 366 } 367 368 @Override 369 public String getNodeValue() throws DOMException { 370 return document.getNodeValue(); 371 } 372 373 @Override 374 public void setNodeValue(String nodeValue) throws DOMException { 375 document.setNodeValue(nodeValue); 376 } 377 378 @Override 379 public short getNodeType() { 380 return document.getNodeType(); 381 } 382 383 @Override 384 public Node getParentNode() { 385 return findIfPresent(document.getParentNode()); 386 } 387 388 @Override 389 public NodeList getChildNodes() { 390 return new NodeListImpl(this, document.getChildNodes()); 391 } 392 393 @Override 394 public Node getFirstChild() { 395 return findIfPresent(document.getFirstChild()); 396 } 397 398 @Override 399 public Node getLastChild() { 400 return findIfPresent(document.getLastChild()); 401 } 402 403 @Override 404 public Node getPreviousSibling() { 405 return findIfPresent(document.getPreviousSibling()); 406 } 407 408 @Override 409 public Node getNextSibling() { 410 return findIfPresent(document.getNextSibling()); 411 } 412 413 @Override 414 public NamedNodeMap getAttributes() { 415 return new NamedNodeMapImpl(document.getAttributes(), this); 416 } 417 418 @Override 419 public Document getOwnerDocument() { 420 return document.getOwnerDocument(); 421 } 422 423 @Override 424 public Node insertBefore(Node newChild, Node refChild) throws DOMException { 425 return document.insertBefore(getDomNode(newChild), getDomNode(refChild)); 426 } 427 428 @Override 429 public Node replaceChild(Node newChild, Node oldChild) throws DOMException { 430 return document.replaceChild(getDomNode(newChild), getDomNode(oldChild)); 431 } 432 433 @Override 434 public Node removeChild(Node oldChild) throws DOMException { 435 return document.removeChild(getDomNode(oldChild)); 436 } 437 438 @Override 439 public Node appendChild(Node newChild) throws DOMException { 440 return document.appendChild(getDomNode(newChild)); 441 } 442 443 @Override 444 public boolean hasChildNodes() { 445 return document.hasChildNodes(); 446 } 447 448 @Override 449 public Node cloneNode(boolean deep) { 450 Node node = document.cloneNode(deep); 451 registerChildNodes(node, deep); 452 return findIfPresent(node); 453 } 454 455 @Override 456 public void normalize() { 457 document.normalize(); 458 } 459 460 @Override 461 public boolean isSupported(String feature, String version) { 462 return document.isSupported(feature, version); 463 } 464 465 @Override 466 public String getNamespaceURI() { 467 return document.getNamespaceURI(); 468 } 469 470 @Override 471 public String getPrefix() { 472 return document.getPrefix(); 473 } 474 475 @Override 476 public void setPrefix(String prefix) throws DOMException { 477 document.setPrefix(prefix); 478 } 479 480 @Override 481 public String getLocalName() { 482 return document.getLocalName(); 483 } 484 485 @Override 486 public boolean hasAttributes() { 487 return document.hasAttributes(); 488 } 489 490 @Override 491 public String getBaseURI() { 492 return document.getBaseURI(); 493 } 494 495 @Override 496 public short compareDocumentPosition(Node other) throws DOMException { 497 return document.compareDocumentPosition(getDomNode(other)); 498 } 499 500 @Override 501 public String getTextContent() throws DOMException { 502 return document.getTextContent(); 503 } 504 505 @Override 506 public void setTextContent(String textContent) throws DOMException { 507 document.setTextContent(textContent); 508 } 509 510 @Override 511 public boolean isSameNode(Node other) { 512 return document.isSameNode(getDomNode(other)); 513 } 514 515 @Override 516 public String lookupPrefix(String namespaceURI) { 517 return document.lookupPrefix(namespaceURI); 518 } 519 520 @Override 521 public boolean isDefaultNamespace(String namespaceURI) { 522 return document.isDefaultNamespace(namespaceURI); 523 } 524 525 @Override 526 public String lookupNamespaceURI(String prefix) { 527 return document.lookupNamespaceURI(prefix); 528 } 529 530 @Override 531 public boolean isEqualNode(Node arg) { 532 return document.isEqualNode(getDomNode(arg)); 533 } 534 535 @Override 536 public Object getFeature(String feature, String version) { 537 return document.getFeature(feature, version); 538 } 539 540 @Override 541 public Object setUserData(String key, Object data, UserDataHandler handler) { 542 return document.setUserData(key, data, handler); 543 } 544 545 @Override 546 public Object getUserData(String key) { 547 return document.getUserData(key); 548 } 549 550 public Document getDomDocument() { 551 return document; 552 } 553 554 /** 555 * Insert a mapping information for {@link org.w3c.dom.Node} - {@link javax.xml.soap.Node}. 556 * 557 * In SAAJ, elements in DOM are expected to be interfaces of SAAJ, on the other hand in JDKs Xerces, 558 * they are casted to internal impl classes. After removal of SAAJ dependency 559 * to JDKs internal classes elements in DOM can never be both of them. 560 * 561 * @param node SAAJ wrapper node for w3c DOM node 562 */ 563 public void register(javax.xml.soap.Node node) { 564 final Node domElement = getDomNode(node); 565 if (domElement.getUserData(SAAJ_NODE) != null) { 566 throw new IllegalStateException("Element " + domElement.getNodeName() 567 + " is already registered"); 568 } 569 domElement.setUserData(SAAJ_NODE, node, null); 570 } 571 572 /** 573 * Find a soap wrapper for w3c dom node. 574 * 575 * @param node w3c dom node nullable 576 * @return soap wrapper for w3c dom node 577 * 578 * @throws 579 */ 580 public javax.xml.soap.Node find(Node node) { 581 return find(node, true); 582 } 583 584 private javax.xml.soap.Node find(Node node, boolean required) { 585 if (node == null) { 586 return null; 587 } 588 if (node instanceof javax.xml.soap.Node) { 589 return (javax.xml.soap.Node) node; 590 } 591 final javax.xml.soap.Node found = (javax.xml.soap.Node) node.getUserData(SAAJ_NODE); 592 if (found == null && required) { 593 throw new IllegalArgumentException(MessageFormat.format("Cannot find SOAP wrapper for element {0}", node)); 594 } 595 return found; 596 } 597 598 /** 599 * If corresponding soap wrapper exists for w3c dom node it is returned, 600 * if not passed dom element is returned. 601 * 602 * @param node w3c dom node 603 * @return soap wrapper or passed w3c dom node if not found 604 */ 605 public Node findIfPresent(Node node) { 606 final javax.xml.soap.Node found = find(node, false); 607 return found != null ? found : node; 608 } 609 610 /** 611 * Extracts w3c dom node from corresponding soap wrapper. 612 * 613 * @param node soap or dom nullable 614 * @return dom node 615 */ 616 public Node getDomNode(Node node) { 617 if (node instanceof SOAPDocumentImpl) { 618 return ((SOAPDocumentImpl)node).getDomElement(); 619 } else if (node instanceof ElementImpl) { 620 return ((ElementImpl) node).getDomElement(); 621 } else if (node instanceof SOAPTextImpl) { 622 return ((SOAPTextImpl)node).getDomElement(); 623 } else if (node instanceof SOAPCommentImpl) { 624 return ((SOAPCommentImpl)node).getDomElement(); 625 } else if (node instanceof CDATAImpl) { 626 return ((CDATAImpl) node).getDomElement(); 627 } 628 return node; 629 } 630 631 632 private Node createSoapNode(Class nodeType, Node node) { 633 if (SOAPTextImpl.class.isAssignableFrom(nodeType)) { 634 return new SOAPTextImpl(this, (Text) node); 635 } else if (SOAPCommentImpl.class.isAssignableFrom(nodeType)) { 636 return new SOAPCommentImpl(this, (Comment) node); 637 } else if (CDATAImpl.class.isAssignableFrom(nodeType)) { 638 return new CDATAImpl(this, (CDATASection) node); 639 } 640 try { 641 Constructor<Node> constructor = nodeType.getConstructor(SOAPDocumentImpl.class, Element.class); 642 return constructor.newInstance(this, node); 643 } catch (Exception e) { 644 throw new IllegalStateException(e); 645 } 646 } 647 648 649 public Document getDomElement() { 650 return document; 651 } 652 653 @Override 654 public String getValue() { 655 throw new UnsupportedOperationException(); 656 } 657 658 @Override 659 public void setValue(String value) { 660 throw new UnsupportedOperationException(); 661 } 662 663 @Override 664 public void setParentElement(SOAPElement parent) throws SOAPException { 665 throw new UnsupportedOperationException(); 666 } 667 668 @Override 669 public SOAPElement getParentElement() { 670 throw new UnsupportedOperationException(); 671 } 672 673 @Override 674 public void detachNode() { 675 throw new UnsupportedOperationException(); 676 } 677 678 @Override 679 public void recycleNode() { 680 throw new UnsupportedOperationException(); 681 } 682 }