/* * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * * @author SAAJ RI Development Team */ package com.sun.xml.internal.messaging.saaj.soap; import com.sun.xml.internal.messaging.saaj.soap.impl.CDATAImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.ElementFactory; import com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.NamedNodeMapImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.NodeListImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.SOAPCommentImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.SOAPTextImpl; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; import com.sun.xml.internal.messaging.saaj.util.SAAJUtil; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.CharacterData; import org.w3c.dom.Comment; import org.w3c.dom.DOMConfiguration; import org.w3c.dom.DOMException; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.EntityReference; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import org.w3c.dom.UserDataHandler; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import java.lang.reflect.Constructor; import java.text.MessageFormat; import java.util.logging.Logger; public class SOAPDocumentImpl implements SOAPDocument, javax.xml.soap.Node, Document { public static final String SAAJ_NODE = "javax.xml.soap.Node"; private static final String XMLNS = "xmlns".intern(); protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); SOAPPartImpl enclosingSOAPPart; private Document document; public SOAPDocumentImpl(SOAPPartImpl enclosingDocument) { document = createDocument(); this.enclosingSOAPPart = enclosingDocument; register(this); } private Document createDocument() { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl", SAAJUtil.getSystemClassLoader()); try { final DocumentBuilder documentBuilder = docFactory.newDocumentBuilder(); return documentBuilder.newDocument(); } catch (ParserConfigurationException e) { throw new RuntimeException("Error creating xml document", e); } } // public SOAPDocumentImpl(boolean grammarAccess) { // super(grammarAccess); // } // // public SOAPDocumentImpl(DocumentType doctype) { // super(doctype); // } // // public SOAPDocumentImpl(DocumentType doctype, boolean grammarAccess) { // super(doctype, grammarAccess); // } @Override public SOAPPartImpl getSOAPPart() { if (enclosingSOAPPart == null) { log.severe("SAAJ0541.soap.fragment.not.bound.to.part"); throw new RuntimeException("Could not complete operation. Fragment not bound to SOAP part."); } return enclosingSOAPPart; } @Override public SOAPDocumentImpl getDocument() { return this; } @Override public DocumentType getDoctype() { // SOAP means no DTD, No DTD means no doctype (SOAP 1.2 only?) return null; } @Override public DOMImplementation getImplementation() { return document.getImplementation(); } @Override public Element getDocumentElement() { // This had better be an Envelope! getSOAPPart().doGetDocumentElement(); return doGetDocumentElement(); } protected Element doGetDocumentElement() { return document.getDocumentElement(); } @Override public Element createElement(String tagName) throws DOMException { return ElementFactory.createElement( this, NameImpl.getLocalNameFromTagName(tagName), NameImpl.getPrefixFromTagName(tagName), null); } @Override public DocumentFragment createDocumentFragment() { return new SOAPDocumentFragment(this); } @Override public org.w3c.dom.Text createTextNode(String data) { return new SOAPTextImpl(this, data); } @Override public Comment createComment(String data) { return new SOAPCommentImpl(this, data); } @Override public CDATASection createCDATASection(String data) throws DOMException { return new CDATAImpl(this, data); } @Override public ProcessingInstruction createProcessingInstruction( String target, String data) throws DOMException { log.severe("SAAJ0542.soap.proc.instructions.not.allowed.in.docs"); throw new UnsupportedOperationException("Processing Instructions are not allowed in SOAP documents"); } @Override public Attr createAttribute(String name) throws DOMException { boolean isQualifiedName = (name.indexOf(":") > 0); if (isQualifiedName) { String nsUri = null; String prefix = name.substring(0, name.indexOf(":")); //cannot do anything to resolve the URI if prefix is not //XMLNS. if (XMLNS.equals(prefix)) { nsUri = ElementImpl.XMLNS_URI; return createAttributeNS(nsUri, name); } } return document.createAttribute(name); } @Override public EntityReference createEntityReference(String name) throws DOMException { log.severe("SAAJ0543.soap.entity.refs.not.allowed.in.docs"); throw new UnsupportedOperationException("Entity References are not allowed in SOAP documents"); } @Override public NodeList getElementsByTagName(String tagname) { return new NodeListImpl(this, document.getElementsByTagName(tagname)); } @Override public org.w3c.dom.Node importNode(Node importedNode, boolean deep) throws DOMException { Node domNode = getDomNode(importedNode); final Node newNode = document.importNode(domNode, deep); if (importedNode instanceof javax.xml.soap.Node) { Node newSoapNode = createSoapNode(importedNode.getClass(), newNode); newNode.setUserData(SAAJ_NODE, newSoapNode, null); if (deep && importedNode.hasChildNodes()) { NodeList childNodes = importedNode.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { registerChildNodes(childNodes.item(i), deep); } } return newSoapNode; } registerChildNodes(newNode, deep); return findIfPresent(newNode); } //If the parentNode is not registered to domToSoap, create soap wapper for parentNode and register it to domToSoap //If deep = true, also register all children of parentNode to domToSoap map. public void registerChildNodes(Node parentNode, boolean deep) { if (parentNode.getUserData(SAAJ_NODE) == null) { if (parentNode instanceof Element) { ElementFactory.createElement(this, (Element) parentNode); } else if (parentNode instanceof CharacterData) { switch (parentNode.getNodeType()) { case CDATA_SECTION_NODE: new CDATAImpl(this, (CharacterData) parentNode); break; case COMMENT_NODE: new SOAPCommentImpl(this, (CharacterData) parentNode); break; case TEXT_NODE: new SOAPTextImpl(this, (CharacterData) parentNode); break; } } } if (deep) { NodeList nodeList = parentNode.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node nextChild = nodeList.item(i); registerChildNodes(nextChild, true); } } } @Override public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException { return ElementFactory.createElement( this, NameImpl.getLocalNameFromTagName(qualifiedName), NameImpl.getPrefixFromTagName(qualifiedName), namespaceURI); } @Override public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { return document.createAttributeNS(namespaceURI, qualifiedName); } @Override public NodeList getElementsByTagNameNS( String namespaceURI, String localName) { return new NodeListImpl(this, document.getElementsByTagNameNS(namespaceURI, localName)); } @Override public Element getElementById(String elementId) { return (Element) findIfPresent(document.getElementById(elementId)); } @Override public String getInputEncoding() { return document.getInputEncoding(); } @Override public String getXmlEncoding() { return document.getXmlEncoding(); } @Override public boolean getXmlStandalone() { return document.getXmlStandalone(); } @Override public void setXmlStandalone(boolean xmlStandalone) throws DOMException { document.setXmlStandalone(xmlStandalone); } @Override public String getXmlVersion() { return document.getXmlVersion(); } @Override public void setXmlVersion(String xmlVersion) throws DOMException { document.setXmlVersion(xmlVersion); } @Override public boolean getStrictErrorChecking() { return document.getStrictErrorChecking(); } @Override public void setStrictErrorChecking(boolean strictErrorChecking) { document.setStrictErrorChecking(strictErrorChecking); } @Override public String getDocumentURI() { return document.getDocumentURI(); } @Override public void setDocumentURI(String documentURI) { document.setDocumentURI(documentURI); } @Override public Node adoptNode(Node source) throws DOMException { return document.adoptNode(source); } @Override public DOMConfiguration getDomConfig() { return document.getDomConfig(); } @Override public void normalizeDocument() { document.normalizeDocument(); } @Override public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException { return findIfPresent(document.renameNode(n, namespaceURI, qualifiedName)); } @Override public String getNodeName() { return document.getNodeName(); } @Override public String getNodeValue() throws DOMException { return document.getNodeValue(); } @Override public void setNodeValue(String nodeValue) throws DOMException { document.setNodeValue(nodeValue); } @Override public short getNodeType() { return document.getNodeType(); } @Override public Node getParentNode() { return findIfPresent(document.getParentNode()); } @Override public NodeList getChildNodes() { return new NodeListImpl(this, document.getChildNodes()); } @Override public Node getFirstChild() { return findIfPresent(document.getFirstChild()); } @Override public Node getLastChild() { return findIfPresent(document.getLastChild()); } @Override public Node getPreviousSibling() { return findIfPresent(document.getPreviousSibling()); } @Override public Node getNextSibling() { return findIfPresent(document.getNextSibling()); } @Override public NamedNodeMap getAttributes() { return new NamedNodeMapImpl(document.getAttributes(), this); } @Override public Document getOwnerDocument() { return document.getOwnerDocument(); } @Override public Node insertBefore(Node newChild, Node refChild) throws DOMException { return document.insertBefore(getDomNode(newChild), getDomNode(refChild)); } @Override public Node replaceChild(Node newChild, Node oldChild) throws DOMException { return document.replaceChild(getDomNode(newChild), getDomNode(oldChild)); } @Override public Node removeChild(Node oldChild) throws DOMException { return document.removeChild(getDomNode(oldChild)); } @Override public Node appendChild(Node newChild) throws DOMException { return document.appendChild(getDomNode(newChild)); } @Override public boolean hasChildNodes() { return document.hasChildNodes(); } @Override public Node cloneNode(boolean deep) { Node node = document.cloneNode(deep); registerChildNodes(node, deep); return findIfPresent(node); } @Override public void normalize() { document.normalize(); } @Override public boolean isSupported(String feature, String version) { return document.isSupported(feature, version); } @Override public String getNamespaceURI() { return document.getNamespaceURI(); } @Override public String getPrefix() { return document.getPrefix(); } @Override public void setPrefix(String prefix) throws DOMException { document.setPrefix(prefix); } @Override public String getLocalName() { return document.getLocalName(); } @Override public boolean hasAttributes() { return document.hasAttributes(); } @Override public String getBaseURI() { return document.getBaseURI(); } @Override public short compareDocumentPosition(Node other) throws DOMException { return document.compareDocumentPosition(getDomNode(other)); } @Override public String getTextContent() throws DOMException { return document.getTextContent(); } @Override public void setTextContent(String textContent) throws DOMException { document.setTextContent(textContent); } @Override public boolean isSameNode(Node other) { return document.isSameNode(getDomNode(other)); } @Override public String lookupPrefix(String namespaceURI) { return document.lookupPrefix(namespaceURI); } @Override public boolean isDefaultNamespace(String namespaceURI) { return document.isDefaultNamespace(namespaceURI); } @Override public String lookupNamespaceURI(String prefix) { return document.lookupNamespaceURI(prefix); } @Override public boolean isEqualNode(Node arg) { return document.isEqualNode(getDomNode(arg)); } @Override public Object getFeature(String feature, String version) { return document.getFeature(feature, version); } @Override public Object setUserData(String key, Object data, UserDataHandler handler) { return document.setUserData(key, data, handler); } @Override public Object getUserData(String key) { return document.getUserData(key); } public Document getDomDocument() { return document; } /** * Insert a mapping information for {@link org.w3c.dom.Node} - {@link javax.xml.soap.Node}. * * In SAAJ, elements in DOM are expected to be interfaces of SAAJ, on the other hand in JDKs Xerces, * they are casted to internal impl classes. After removal of SAAJ dependency * to JDKs internal classes elements in DOM can never be both of them. * * @param node SAAJ wrapper node for w3c DOM node */ public void register(javax.xml.soap.Node node) { final Node domElement = getDomNode(node); if (domElement.getUserData(SAAJ_NODE) != null) { throw new IllegalStateException("Element " + domElement.getNodeName() + " is already registered"); } domElement.setUserData(SAAJ_NODE, node, null); } /** * Find a soap wrapper for w3c dom node. * * @param node w3c dom node nullable * @return soap wrapper for w3c dom node * * @throws */ public javax.xml.soap.Node find(Node node) { return find(node, true); } private javax.xml.soap.Node find(Node node, boolean required) { if (node == null) { return null; } if (node instanceof javax.xml.soap.Node) { return (javax.xml.soap.Node) node; } final javax.xml.soap.Node found = (javax.xml.soap.Node) node.getUserData(SAAJ_NODE); if (found == null && required) { throw new IllegalArgumentException(MessageFormat.format("Cannot find SOAP wrapper for element {0}", node)); } return found; } /** * If corresponding soap wrapper exists for w3c dom node it is returned, * if not passed dom element is returned. * * @param node w3c dom node * @return soap wrapper or passed w3c dom node if not found */ public Node findIfPresent(Node node) { final javax.xml.soap.Node found = find(node, false); return found != null ? found : node; } /** * Extracts w3c dom node from corresponding soap wrapper. * * @param node soap or dom nullable * @return dom node */ public Node getDomNode(Node node) { if (node instanceof SOAPDocumentImpl) { return ((SOAPDocumentImpl)node).getDomElement(); } else if (node instanceof ElementImpl) { return ((ElementImpl) node).getDomElement(); } else if (node instanceof SOAPTextImpl) { return ((SOAPTextImpl)node).getDomElement(); } else if (node instanceof SOAPCommentImpl) { return ((SOAPCommentImpl)node).getDomElement(); } else if (node instanceof CDATAImpl) { return ((CDATAImpl) node).getDomElement(); } return node; } private Node createSoapNode(Class nodeType, Node node) { if (SOAPTextImpl.class.isAssignableFrom(nodeType)) { return new SOAPTextImpl(this, (Text) node); } else if (SOAPCommentImpl.class.isAssignableFrom(nodeType)) { return new SOAPCommentImpl(this, (Comment) node); } else if (CDATAImpl.class.isAssignableFrom(nodeType)) { return new CDATAImpl(this, (CDATASection) node); } try { Constructor constructor = nodeType.getConstructor(SOAPDocumentImpl.class, Element.class); return constructor.newInstance(this, node); } catch (Exception e) { throw new IllegalStateException(e); } } public Document getDomElement() { return document; } @Override public String getValue() { throw new UnsupportedOperationException(); } @Override public void setValue(String value) { throw new UnsupportedOperationException(); } @Override public void setParentElement(SOAPElement parent) throws SOAPException { throw new UnsupportedOperationException(); } @Override public SOAPElement getParentElement() { throw new UnsupportedOperationException(); } @Override public void detachNode() { throw new UnsupportedOperationException(); } @Override public void recycleNode() { throw new UnsupportedOperationException(); } }