/* * Copyright (c) 1997, 2014, 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. */ package com.sun.xml.internal.messaging.saaj.soap; import java.io.*; import java.util.Iterator; import java.util.logging.Logger; import java.util.logging.Level; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.xml.soap.*; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.*; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeBodyPart; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl; import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; import com.sun.xml.internal.messaging.saaj.util.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; /** * SOAPPartImpl is the first attachment. This contains the XML/SOAP document. * * @author Anil Vijendran (anil@sun.com) */ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); protected MimeHeaders headers; protected Envelope envelope; protected Source source; protected SOAPDocumentImpl document; //flag to indicate if a setContent happened. private boolean sourceWasSet = false; // Records whether the input source had an xml decl or not. protected boolean omitXmlDecl = true; // Records the charset encoding of the input stream source if provided. protected String sourceCharsetEncoding = null; /** * Reference to containing message (may be null) */ protected MessageImpl message; static final boolean lazyContentLength; static { lazyContentLength = SAAJUtil.getSystemBoolean("saaj.lazy.contentlength"); } protected SOAPPartImpl() { this(null); } protected SOAPPartImpl(MessageImpl message) { document = new SOAPDocumentImpl(this); headers = new MimeHeaders(); this.message = message; headers.setHeader("Content-Type", getContentType()); } protected abstract String getContentType(); protected abstract Envelope createEnvelopeFromSource() throws SOAPException; protected abstract Envelope createEmptyEnvelope(String prefix) throws SOAPException; protected abstract SOAPPartImpl duplicateType(); protected String getContentTypeString() { return getContentType(); } public boolean isFastInfoset() { return (message != null) ? message.isFastInfoset() : false; } public SOAPEnvelope getEnvelope() throws SOAPException { // If there is no SOAP envelope already created, then create // one from a source if one exists. If there is a newer source // then use that source. if (sourceWasSet) sourceWasSet = false; lookForEnvelope(); if (envelope != null) { if (source != null) { // there's a newer source, use it document.removeChild(envelope); envelope = createEnvelopeFromSource(); } } else if (source != null) { envelope = createEnvelopeFromSource(); } else { envelope = createEmptyEnvelope(null); document.insertBefore(envelope, null); } return envelope; } protected void lookForEnvelope() throws SOAPException { Element envelopeChildElement = document.doGetDocumentElement(); if (envelopeChildElement == null || envelopeChildElement instanceof Envelope) { envelope = (EnvelopeImpl) envelopeChildElement; } else if (!(envelopeChildElement instanceof ElementImpl)) { log.severe("SAAJ0512.soap.incorrect.factory.used"); throw new SOAPExceptionImpl("Unable to create envelope: incorrect factory used during tree construction"); } else { ElementImpl soapElement = (ElementImpl) envelopeChildElement; if (soapElement.getLocalName().equalsIgnoreCase("Envelope")) { String prefix = soapElement.getPrefix(); String uri = (prefix == null) ? soapElement.getNamespaceURI() : soapElement.getNamespaceURI(prefix); if(!uri.equals(NameImpl.SOAP11_NAMESPACE) && !uri.equals(NameImpl.SOAP12_NAMESPACE)) { log.severe("SAAJ0513.soap.unknown.ns"); throw new SOAPVersionMismatchException("Unable to create envelope from given source because the namespace was not recognized"); } } else { log.severe("SAAJ0514.soap.root.elem.not.named.envelope"); throw new SOAPExceptionImpl( "Unable to create envelope from given source because the root element is not named \"Envelope\""); } } } public void removeAllMimeHeaders() { headers.removeAllHeaders(); } public void removeMimeHeader(String header) { headers.removeHeader(header); } public String[] getMimeHeader(String name) { return headers.getHeader(name); } public void setMimeHeader(String name, String value) { headers.setHeader(name, value); } public void addMimeHeader(String name, String value) { headers.addHeader(name, value); } public Iterator getAllMimeHeaders() { return headers.getAllHeaders(); } public Iterator getMatchingMimeHeaders(String[] names) { return headers.getMatchingHeaders(names); } public Iterator getNonMatchingMimeHeaders(String[] names) { return headers.getNonMatchingHeaders(names); } public Source getContent() throws SOAPException { if (source != null) { InputStream bis = null; if (source instanceof JAXMStreamSource) { StreamSource streamSource = (StreamSource)source; bis = streamSource.getInputStream(); } else if (FastInfosetReflection.isFastInfosetSource(source)) { // FastInfosetSource inherits from SAXSource SAXSource saxSource = (SAXSource)source; bis = saxSource.getInputSource().getByteStream(); } if (bis != null) { try { bis.reset(); } catch (IOException e) { /* This exception will never be thrown. * * The setContent method will modify the source * if StreamSource to JAXMStreamSource, that uses * a ByteInputStream, and for a FastInfosetSource will * replace the InputStream with a ByteInputStream. */ } } return source; } return ((Envelope) getEnvelope()).getContent(); } public void setContent(Source source) throws SOAPException { try { if (source instanceof StreamSource) { InputStream is = ((StreamSource) source).getInputStream(); Reader rdr = ((StreamSource) source).getReader(); if (is != null) { this.source = new JAXMStreamSource(is); } else if (rdr != null) { this.source = new JAXMStreamSource(rdr); } else { log.severe("SAAJ0544.soap.no.valid.reader.for.src"); throw new SOAPExceptionImpl("Source does not have a valid Reader or InputStream"); } } else if (FastInfosetReflection.isFastInfosetSource(source)) { // InputStream is = source.getInputStream() InputStream is = FastInfosetReflection.FastInfosetSource_getInputStream(source); /* * Underlying stream must be ByteInputStream for getContentAsStream(). We pay the * cost of copying the underlying bytes here to avoid multiple copies every time * getBytes() is called on a ByteInputStream. */ if (!(is instanceof ByteInputStream)) { ByteOutputStream bout = null; try { bout = new ByteOutputStream(); bout.write(is); // source.setInputStream(new ByteInputStream(...)) FastInfosetReflection.FastInfosetSource_setInputStream( source, bout.newInputStream()); } finally { if (bout != null) bout.close(); } } this.source = source; } else { this.source = source; } sourceWasSet = true; } catch (Exception ex) { ex.printStackTrace(); log.severe("SAAJ0545.soap.cannot.set.src.for.part"); throw new SOAPExceptionImpl( "Error setting the source for SOAPPart: " + ex.getMessage()); } } public InputStream getContentAsStream() throws IOException { if (source != null) { InputStream is = null; // Allow message to be transcode if so requested if (source instanceof StreamSource && !isFastInfoset()) { is = ((StreamSource) source).getInputStream(); } else if (FastInfosetReflection.isFastInfosetSource(source) && isFastInfoset()) { try { // InputStream is = source.getInputStream() is = FastInfosetReflection.FastInfosetSource_getInputStream(source); } catch (Exception e) { throw new IOException(e.toString()); } } if (is != null) { if (lazyContentLength) { return is; } if (!(is instanceof ByteInputStream)) { log.severe("SAAJ0546.soap.stream.incorrect.type"); throw new IOException("Internal error: stream not of the right type"); } return (ByteInputStream) is; } // need to do something here for reader... // for now we'll see if we can fallback... } ByteOutputStream b = new ByteOutputStream(); Envelope env = null; try { env = (Envelope) getEnvelope(); env.output(b, isFastInfoset()); } catch (SOAPException soapException) { log.severe("SAAJ0547.soap.cannot.externalize"); throw new SOAPIOException( "SOAP exception while trying to externalize: ", soapException); } return b.newInputStream(); } MimeBodyPart getMimePart() throws SOAPException { try { MimeBodyPart headerEnvelope = new MimeBodyPart(); headerEnvelope.setDataHandler(getDataHandler()); AttachmentPartImpl.copyMimeHeaders(headers, headerEnvelope); return headerEnvelope; } catch (SOAPException ex) { throw ex; } catch (Exception ex) { log.severe("SAAJ0548.soap.cannot.externalize.hdr"); throw new SOAPExceptionImpl("Unable to externalize header", ex); } } MimeHeaders getMimeHeaders() { return headers; } DataHandler getDataHandler() { DataSource ds = new DataSource() { public OutputStream getOutputStream() throws IOException { throw new IOException("Illegal Operation"); } public String getContentType() { return getContentTypeString(); } public String getName() { return getContentId(); } public InputStream getInputStream() throws IOException { return getContentAsStream(); } }; return new DataHandler(ds); } public SOAPDocumentImpl getDocument() { handleNewSource(); return document; } public SOAPPartImpl getSOAPPart() { return this; } public DocumentType getDoctype() { return document.getDoctype(); } // Forward all of these calls to the document to ensure that they work the // same way whether they are called from here or directly from the document. // If the document needs any help from this SOAPPart then // Make it use a call-back as in doGetDocumentElement() below public DOMImplementation getImplementation() { return document.getImplementation(); } public Element getDocumentElement() { // If there is no SOAP envelope already created, then create // one from a source if one exists. If there is a newer source // then use that source. try { getEnvelope(); } catch (SOAPException e) { } return document.getDocumentElement(); } protected void doGetDocumentElement() { handleNewSource(); try { lookForEnvelope(); } catch (SOAPException e) { } } public Element createElement(String tagName) throws DOMException { return document.createElement(tagName); } public DocumentFragment createDocumentFragment() { return document.createDocumentFragment(); } public org.w3c.dom.Text createTextNode(String data) { return document.createTextNode(data); } public Comment createComment(String data) { return document.createComment(data); } public CDATASection createCDATASection(String data) throws DOMException { return document.createCDATASection(data); } public ProcessingInstruction createProcessingInstruction( String target, String data) throws DOMException { return document.createProcessingInstruction(target, data); } public Attr createAttribute(String name) throws DOMException { return document.createAttribute(name); } public EntityReference createEntityReference(String name) throws DOMException { return document.createEntityReference(name); } public NodeList getElementsByTagName(String tagname) { handleNewSource(); return document.getElementsByTagName(tagname); } public org.w3c.dom.Node importNode( org.w3c.dom.Node importedNode, boolean deep) throws DOMException { handleNewSource(); return document.importNode(importedNode, deep); } public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException { return document.createElementNS(namespaceURI, qualifiedName); } public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { return document.createAttributeNS(namespaceURI, qualifiedName); } public NodeList getElementsByTagNameNS( String namespaceURI, String localName) { handleNewSource(); return document.getElementsByTagNameNS(namespaceURI, localName); } public Element getElementById(String elementId) { handleNewSource(); return document.getElementById(elementId); } public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild) throws DOMException { handleNewSource(); return document.appendChild(newChild); } public org.w3c.dom.Node cloneNode(boolean deep) { handleNewSource(); return document.cloneNode(deep); } protected SOAPPartImpl doCloneNode() { handleNewSource(); SOAPPartImpl newSoapPart = duplicateType(); newSoapPart.headers = MimeHeadersUtil.copy(this.headers); newSoapPart.source = this.source; return newSoapPart; } public NamedNodeMap getAttributes() { return document.getAttributes(); } public NodeList getChildNodes() { handleNewSource(); return document.getChildNodes(); } public org.w3c.dom.Node getFirstChild() { handleNewSource(); return document.getFirstChild(); } public org.w3c.dom.Node getLastChild() { handleNewSource(); return document.getLastChild(); } public String getLocalName() { return document.getLocalName(); } public String getNamespaceURI() { return document.getNamespaceURI(); } public org.w3c.dom.Node getNextSibling() { handleNewSource(); return document.getNextSibling(); } public String getNodeName() { return document.getNodeName(); } public short getNodeType() { return document.getNodeType(); } public String getNodeValue() throws DOMException { return document.getNodeValue(); } public Document getOwnerDocument() { return document.getOwnerDocument(); } public org.w3c.dom.Node getParentNode() { return document.getParentNode(); } public String getPrefix() { return document.getPrefix(); } public org.w3c.dom.Node getPreviousSibling() { return document.getPreviousSibling(); } public boolean hasAttributes() { return document.hasAttributes(); } public boolean hasChildNodes() { handleNewSource(); return document.hasChildNodes(); } public org.w3c.dom.Node insertBefore( org.w3c.dom.Node arg0, org.w3c.dom.Node arg1) throws DOMException { handleNewSource(); return document.insertBefore(arg0, arg1); } public boolean isSupported(String arg0, String arg1) { return document.isSupported(arg0, arg1); } public void normalize() { handleNewSource(); document.normalize(); } public org.w3c.dom.Node removeChild(org.w3c.dom.Node arg0) throws DOMException { handleNewSource(); return document.removeChild(arg0); } public org.w3c.dom.Node replaceChild( org.w3c.dom.Node arg0, org.w3c.dom.Node arg1) throws DOMException { handleNewSource(); return document.replaceChild(arg0, arg1); } public void setNodeValue(String arg0) throws DOMException { document.setNodeValue(arg0); } public void setPrefix(String arg0) throws DOMException { document.setPrefix(arg0); } private void handleNewSource() { if (sourceWasSet) { // There is a newer source use that source. try { getEnvelope(); } catch (SOAPException e) { } } } protected XMLDeclarationParser lookForXmlDecl() throws SOAPException { if ((source != null) && (source instanceof StreamSource)) { Reader reader = null; InputStream inputStream = ((StreamSource) source).getInputStream(); if (inputStream != null) { if (getSourceCharsetEncoding() == null) { reader = new InputStreamReader(inputStream); } else { try { reader = new InputStreamReader( inputStream, getSourceCharsetEncoding()); } catch (UnsupportedEncodingException uee) { log.log( Level.SEVERE, "SAAJ0551.soap.unsupported.encoding", new Object[] {getSourceCharsetEncoding()}); throw new SOAPExceptionImpl( "Unsupported encoding " + getSourceCharsetEncoding(), uee); } } } else { reader = ((StreamSource) source).getReader(); } if (reader != null) { PushbackReader pushbackReader = new PushbackReader(reader, 4096); //some size to unread XMLDeclarationParser ev = new XMLDeclarationParser(pushbackReader); try { ev.parse(); } catch (Exception e) { log.log( Level.SEVERE, "SAAJ0552.soap.xml.decl.parsing.failed"); throw new SOAPExceptionImpl( "XML declaration parsing failed", e); } String xmlDecl = ev.getXmlDeclaration(); if ((xmlDecl != null) && (xmlDecl.length() > 0)) { this.omitXmlDecl = false; } if (lazyContentLength) { source = new StreamSource(pushbackReader); } return ev; } } else if ((source != null) && (source instanceof DOMSource)) { //TODO: A Domsource maynot contain XMLDecl ?. } return null; } public void setSourceCharsetEncoding(String charset) { this.sourceCharsetEncoding = charset; } public org.w3c.dom.Node renameNode(org.w3c.dom.Node n, String namespaceURI, String qualifiedName) throws DOMException { handleNewSource(); return document.renameNode(n, namespaceURI, qualifiedName); } public void normalizeDocument() { document.normalizeDocument(); } public DOMConfiguration getDomConfig() { return document.getDomConfig(); } public org.w3c.dom.Node adoptNode(org.w3c.dom.Node source) throws DOMException { handleNewSource(); return document.adoptNode(source); } public void setDocumentURI(String documentURI) { document.setDocumentURI(documentURI); } public String getDocumentURI() { return document.getDocumentURI(); } public void setStrictErrorChecking(boolean strictErrorChecking) { document.setStrictErrorChecking(strictErrorChecking); } public String getInputEncoding() { return document.getInputEncoding(); } public String getXmlEncoding() { return document.getXmlEncoding(); } public boolean getXmlStandalone() { return document.getXmlStandalone(); } public void setXmlStandalone(boolean xmlStandalone) throws DOMException { document.setXmlStandalone(xmlStandalone); } public String getXmlVersion() { return document.getXmlVersion(); } public void setXmlVersion(String xmlVersion) throws DOMException { document.setXmlVersion(xmlVersion); } public boolean getStrictErrorChecking() { return document.getStrictErrorChecking(); } // DOM L3 methods from org.w3c.dom.Node public String getBaseURI() { return document.getBaseURI(); } public short compareDocumentPosition(org.w3c.dom.Node other) throws DOMException { return document.compareDocumentPosition(other); } public String getTextContent() throws DOMException { return document.getTextContent(); } public void setTextContent(String textContent) throws DOMException { document.setTextContent(textContent); } public boolean isSameNode(org.w3c.dom.Node other) { return document.isSameNode(other); } public String lookupPrefix(String namespaceURI) { return document.lookupPrefix(namespaceURI); } public boolean isDefaultNamespace(String namespaceURI) { return document.isDefaultNamespace(namespaceURI); } public String lookupNamespaceURI(String prefix) { return document.lookupNamespaceURI(prefix); } public boolean isEqualNode(org.w3c.dom.Node arg) { return document.isEqualNode(arg); } public Object getFeature(String feature, String version) { return document.getFeature(feature,version); } public Object setUserData(String key, Object data, UserDataHandler handler) { return document.setUserData(key, data, handler); } public Object getUserData(String key) { return document.getUserData(key); } public void recycleNode() { // Nothing seems to be required to be done here } public String getValue() { return null; } public void setValue(String value) { log.severe("SAAJ0571.soappart.setValue.not.defined"); throw new IllegalStateException("Setting value of a soap part is not defined"); } public void setParentElement(SOAPElement parent) throws SOAPException { log.severe("SAAJ0570.soappart.parent.element.not.defined"); throw new SOAPExceptionImpl("The parent element of a soap part is not defined"); } public SOAPElement getParentElement() { return null; } public void detachNode() { // Nothing seems to be required to be done here } public String getSourceCharsetEncoding() { return sourceCharsetEncoding; } public abstract String getSOAPNamespace(); }