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.impl; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.io.OutputStreamWriter; 31 32 import java.util.logging.Level; 33 34 import javax.xml.namespace.QName; 35 import javax.xml.soap.*; 36 import javax.xml.stream.XMLStreamException; 37 import javax.xml.stream.XMLStreamReader; 38 import javax.xml.stream.XMLStreamWriter; 39 import javax.xml.transform.*; 40 import javax.xml.transform.dom.DOMSource; 41 import javax.xml.transform.stream.StreamResult; 42 43 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; 44 import com.sun.xml.internal.messaging.saaj.soap.LazyEnvelope; 45 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; 46 import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; 47 import com.sun.xml.internal.messaging.saaj.soap.StaxLazySourceBridge; 48 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; 49 import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; 50 import com.sun.xml.internal.messaging.saaj.util.stax.LazyEnvelopeStaxReader; 51 import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; 52 53 import com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader; 54 import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; 55 import org.w3c.dom.Element; 56 57 /** 58 * Our implementation of the SOAP envelope. 59 * 60 * @author Anil Vijendran (anil@sun.com) 61 */ 62 public abstract class EnvelopeImpl extends ElementImpl implements LazyEnvelope { 63 protected HeaderImpl header; 64 protected BodyImpl body; 65 String omitXmlDecl = "yes"; 66 String charset = "utf-8"; 67 String xmlDecl = null; 68 69 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, Name name) { 70 super(ownerDoc, name); 71 } 72 73 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, QName name) { 74 super(ownerDoc, name); 75 } 76 77 protected EnvelopeImpl( 78 SOAPDocumentImpl ownerDoc, 79 NameImpl name, 80 boolean createHeader, 81 boolean createBody) 82 throws SOAPException { 83 this(ownerDoc, name); 84 85 ensureNamespaceIsDeclared( 86 getElementQName().getPrefix(), getElementQName().getNamespaceURI()); 87 88 // XXX 89 if (createHeader) 90 addHeader(); 91 92 if (createBody) 93 addBody(); 94 } 95 96 public EnvelopeImpl(SOAPDocumentImpl ownerDoc, Element domElement) { 97 super(ownerDoc, domElement); 98 } 99 100 protected abstract NameImpl getHeaderName(String prefix); 101 protected abstract NameImpl getBodyName(String prefix); 102 103 public SOAPHeader addHeader() throws SOAPException { 104 return addHeader(null); 105 } 106 107 public SOAPHeader addHeader(String prefix) throws SOAPException { 108 109 if (prefix == null || prefix.equals("")) { 110 prefix = getPrefix(); 111 } 112 113 NameImpl headerName = getHeaderName(prefix); 114 NameImpl bodyName = getBodyName(prefix); 115 116 HeaderImpl header = null; 117 SOAPElement firstChild = (SOAPElement) getFirstChildElement(); 118 119 if (firstChild != null) { 120 if (firstChild.getElementName().equals(headerName)) { 121 log.severe("SAAJ0120.impl.header.already.exists"); 122 throw new SOAPExceptionImpl("Can't add a header when one is already present."); 123 } else if (!firstChild.getElementName().equals(bodyName)) { 124 log.severe("SAAJ0121.impl.invalid.first.child.of.envelope"); 125 throw new SOAPExceptionImpl("First child of Envelope must be either a Header or Body"); 126 } 127 } 128 129 header = (HeaderImpl) createElement(headerName); 130 insertBefore(header.getDomElement(), firstChild); 131 header.ensureNamespaceIsDeclared(headerName.getPrefix(), headerName.getURI()); 132 133 return header; 134 } 135 136 protected void lookForHeader() throws SOAPException { 137 NameImpl headerName = getHeaderName(null); 138 139 HeaderImpl hdr = (HeaderImpl) findChild(headerName); 140 header = hdr; 141 } 142 143 public SOAPHeader getHeader() throws SOAPException { 144 lookForHeader(); 145 return header; 146 } 147 148 protected void lookForBody() throws SOAPException { 149 NameImpl bodyName = getBodyName(null); 150 151 BodyImpl bodyChildElement = (BodyImpl) findChild(bodyName); 152 body = bodyChildElement; 153 } 154 155 public SOAPBody addBody() throws SOAPException { 156 return addBody(null); 157 } 158 159 public SOAPBody addBody(String prefix) throws SOAPException { 160 lookForBody(); 161 162 if (prefix == null || prefix.equals("")) { 163 prefix = getPrefix(); 164 } 165 166 if (body == null) { 167 NameImpl bodyName = getBodyName(prefix); 168 body = (BodyImpl) createElement(bodyName); 169 insertBefore(body.getDomElement(), null); 170 body.ensureNamespaceIsDeclared(bodyName.getPrefix(), bodyName.getURI()); 171 } else { 172 log.severe("SAAJ0122.impl.body.already.exists"); 173 throw new SOAPExceptionImpl("Can't add a body when one is already present."); 174 } 175 176 return body; 177 } 178 179 protected SOAPElement addElement(Name name) throws SOAPException { 180 if (getBodyName(null).equals(name)) { 181 return addBody(name.getPrefix()); 182 } 183 if (getHeaderName(null).equals(name)) { 184 return addHeader(name.getPrefix()); 185 } 186 187 return super.addElement(name); 188 } 189 190 protected SOAPElement addElement(QName name) throws SOAPException { 191 if (getBodyName(null).equals(NameImpl.convertToName(name))) { 192 return addBody(name.getPrefix()); 193 } 194 if (getHeaderName(null).equals(NameImpl.convertToName(name))) { 195 return addHeader(name.getPrefix()); 196 } 197 198 return super.addElement(name); 199 } 200 201 public SOAPBody getBody() throws SOAPException { 202 lookForBody(); 203 return body; 204 } 205 206 public Source getContent() { 207 return new DOMSource(getOwnerDocument()); 208 } 209 210 public Name createName(String localName, String prefix, String uri) 211 throws SOAPException { 212 213 // validating parameters before passing them on 214 // to make sure that the namespace specification rules are followed 215 216 // reserved xmlns prefix cannot be used. 217 if ("xmlns".equals(prefix)) { 218 log.severe("SAAJ0123.impl.no.reserved.xmlns"); 219 throw new SOAPExceptionImpl("Cannot declare reserved xmlns prefix"); 220 } 221 // Qualified name cannot be xmlns. 222 if ((prefix == null) && ("xmlns".equals(localName))) { 223 log.severe("SAAJ0124.impl.qualified.name.cannot.be.xmlns"); 224 throw new SOAPExceptionImpl("Qualified name cannot be xmlns"); 225 } 226 227 return NameImpl.create(localName, prefix, uri); 228 } 229 230 public Name createName(String localName, String prefix) 231 throws SOAPException { 232 String namespace = getNamespaceURI(prefix); 233 if (namespace == null) { 234 log.log( 235 Level.SEVERE, 236 "SAAJ0126.impl.cannot.locate.ns", 237 new String[] { prefix }); 238 throw new SOAPExceptionImpl( 239 "Unable to locate namespace for prefix " + prefix); 240 } 241 return NameImpl.create(localName, prefix, namespace); 242 } 243 244 public Name createName(String localName) throws SOAPException { 245 return NameImpl.createFromUnqualifiedName(localName); 246 } 247 248 public void setOmitXmlDecl(String value) { 249 this.omitXmlDecl = value; 250 } 251 252 public void setXmlDecl(String value) { 253 this.xmlDecl = value; 254 } 255 256 public void setCharsetEncoding(String value) { 257 charset = value; 258 } 259 260 public void output(OutputStream out) throws IOException { 261 try { 262 // materializeBody(); 263 Transformer transformer = 264 EfficientStreamingTransformer.newTransformer(); 265 266 transformer.setOutputProperty( 267 OutputKeys.OMIT_XML_DECLARATION, "yes"); 268 /*omitXmlDecl);*/ 269 // no equivalent for "setExpandEmptyElements" 270 transformer.setOutputProperty( 271 OutputKeys.ENCODING, 272 charset); 273 274 if (omitXmlDecl.equals("no") && xmlDecl == null) { 275 xmlDecl = "<?xml version=\"" + getOwnerDocument().getXmlVersion() + "\" encoding=\"" + 276 charset + "\" ?>"; 277 } 278 279 StreamResult result = new StreamResult(out); 280 if (xmlDecl != null) { 281 OutputStreamWriter writer = new OutputStreamWriter(out, charset); 282 writer.write(xmlDecl); 283 writer.flush(); 284 result = new StreamResult(writer); 285 } 286 287 if (log.isLoggable(Level.FINE)) { 288 log.log(Level.FINE, "SAAJ0190.impl.set.xml.declaration", 289 new String[] { omitXmlDecl }); 290 log.log(Level.FINE, "SAAJ0191.impl.set.encoding", 291 new String[] { charset }); 292 } 293 294 //StreamResult result = new StreamResult(out); 295 transformer.transform(getContent(), result); 296 } catch (Exception ex) { 297 throw new IOException(ex.getMessage()); 298 } 299 } 300 301 /** 302 * Serialize to FI if boolean parameter set. 303 */ 304 public void output(OutputStream out, boolean isFastInfoset) 305 throws IOException 306 { 307 if (!isFastInfoset) { 308 output(out); 309 } 310 else { 311 try { 312 // Run transform and generate FI output from content 313 Transformer transformer = EfficientStreamingTransformer.newTransformer(); 314 transformer.transform(getContent(), 315 FastInfosetReflection.FastInfosetResult_new(out)); 316 } 317 catch (Exception ex) { 318 throw new IOException(ex.getMessage()); 319 } 320 } 321 } 322 323 // public void prettyPrint(OutputStream out) throws IOException { 324 // if (getDocument() == null) 325 // initDocument(); 326 // 327 // OutputFormat format = OutputFormat.createPrettyPrint(); 328 // 329 // format.setIndentSize(2); 330 // format.setNewlines(true); 331 // format.setTrimText(true); 332 // format.setPadText(true); 333 // format.setExpandEmptyElements(false); 334 // 335 // XMLWriter writer = new XMLWriter(out, format); 336 // writer.write(getDocument()); 337 // } 338 // 339 // public void prettyPrint(Writer out) throws IOException { 340 // if (getDocument() == null) 341 // initDocument(); 342 // 343 // OutputFormat format = OutputFormat.createPrettyPrint(); 344 // 345 // format.setIndentSize(2); 346 // format.setNewlines(true); 347 // format.setTrimText(true); 348 // format.setPadText(true); 349 // format.setExpandEmptyElements(false); 350 // 351 // XMLWriter writer = new XMLWriter(out, format); 352 // writer.write(getDocument()); 353 // } 354 355 356 public SOAPElement setElementQName(QName newName) throws SOAPException { 357 log.log(Level.SEVERE, 358 "SAAJ0146.impl.invalid.name.change.requested", 359 new Object[] {elementQName.getLocalPart(), 360 newName.getLocalPart()}); 361 throw new SOAPException("Cannot change name for " 362 + elementQName.getLocalPart() + " to " 363 + newName.getLocalPart()); 364 } 365 366 @Override 367 public void setStaxBridge(StaxBridge bridge) throws SOAPException { 368 //set it on the body 369 ((BodyImpl) getBody()).setStaxBridge(bridge); 370 } 371 372 @Override 373 public StaxBridge getStaxBridge() throws SOAPException { 374 return ((BodyImpl) getBody()).getStaxBridge(); 375 } 376 377 @Override 378 public XMLStreamReader getPayloadReader() throws SOAPException { 379 return ((BodyImpl) getBody()).getPayloadReader(); 380 } 381 382 @Override 383 public void writeTo(final XMLStreamWriter writer) throws XMLStreamException, SOAPException { 384 StaxBridge readBridge = this.getStaxBridge(); 385 if (readBridge != null && readBridge instanceof StaxLazySourceBridge) { 386 // StaxSoapWriteBridge writingBridge = new StaxSoapWriteBridge(this); 387 // writingBridge.write(writer); 388 final String soapEnvNS = this.getNamespaceURI(); 389 final DOMStreamReader reader = new DOMStreamReader(this); 390 XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); 391 writingBridge.bridge( new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, writer) { 392 public boolean proceedAfterStartElement() { 393 if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ 394 return false; 395 } else 396 return true; 397 } 398 });//bridgeToBodyStartTag 399 ((StaxLazySourceBridge)readBridge).writePayloadTo(writer); 400 writer.writeEndElement();//body 401 writer.writeEndElement();//env 402 writer.writeEndDocument(); 403 writer.flush(); 404 } else { 405 LazyEnvelopeStaxReader lazyEnvReader = new LazyEnvelopeStaxReader(this); 406 XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); 407 writingBridge.bridge(lazyEnvReader, writer); 408 // writingBridge.bridge(new XMLStreamReaderToXMLStreamWriter.Breakpoint(lazyEnvReader, writer)); 409 } 410 //Assume the staxBridge is exhausted now since we would have read the body reader 411 ((BodyImpl) getBody()).setPayloadStreamRead(); 412 } 413 414 @Override 415 public QName getPayloadQName() throws SOAPException { 416 return ((BodyImpl) getBody()).getPayloadQName(); 417 } 418 419 @Override 420 public String getPayloadAttributeValue(String localName) throws SOAPException { 421 return ((BodyImpl) getBody()).getPayloadAttributeValue(localName); 422 } 423 424 @Override 425 public String getPayloadAttributeValue(QName qName) throws SOAPException { 426 return ((BodyImpl) getBody()).getPayloadAttributeValue(qName); 427 } 428 429 @Override 430 public boolean isLazy() { 431 try { 432 return ((BodyImpl) getBody()).isLazy(); 433 } catch (SOAPException e) { 434 return false; 435 } 436 } 437 438 }